feat: configuration enablement — env-var defaults + source resilience
Six small additive changes that make the skill correctly understand its configured sources, plus tests + docs. User-visible benefits - LAST30DAYS_STORE=1 in .env turns persistence default-on without remembering --store on every invocation. Mirrors LAST30DAYS_DEBUG / LAST30DAYS_SKIP_PREFLIGHT convention. - SCRAPE_CREATORS_API_KEY (with underscore) accepted as alias for the canonical name. Matches the spelling used in the vendor's own example code (Adrian Horning's repo); saves the next user the same diagnostic rabbit hole. - Bluesky search now hits api.bsky.app (canonical AppView) instead of public.api.bsky.app (BunnyCDN-blocked public mirror as of 2026-05-04). BSKY_SEARCH_HOST env var lets users self-rescue future host migrations without a code release. Pre-fix: silent 0 Bluesky posts on every run. - App-password format validator emits a one-shot stderr warning when BSKY_APP_PASSWORD doesn't match xxxx-xxxx-xxxx-xxxx form. Detect-don't- gate: createSession still accepts main passwords; the warning helps users identify a hygiene issue without breaking existing setups. - Instagram retry on multi-token 500. SC's v2 reels endpoint wraps Google Search and 500's frequently on multi-word queries; a hashtag- form retry runs once before bubbling up. Documented vendor instability. - LAST30DAYS_TRANSCRIPT_TIMEOUT env var (default 30s, was hardcoded 15s). SC's transcript endpoint regularly takes >15s; the old default was clipping legitimate responses. - Silent-failure visibility: new bonus_errored field in the quality nudge fires when SC is configured but Instagram returned 0 items. Users see "Bonus source silent: Instagram" instead of unexplained absence. - YouTube degraded-ratio false-positive fixed. Captions-disabled videos can never produce a transcript regardless of yt-dlp version; they're now subtracted from the denominator so a single uploader-disabled video doesn't false-trigger the "stale yt-dlp" nudge. - urllib retry path: status_code attribute typo fix. The Instagram 500-retry was dead code on the urllib branch (getattr(e, 'status', ...) while http.HTTPError exposes status_code). Docs - README.md: added /plugin install last30days step after marketplace add in three places (the install was previously omitted in the docs). - CONFIGURATION.md: documented LAST30DAYS_STORE env var, added BSKY_SEARCH_HOST + app-password format section, mentioned LAST30DAYS_TRANSCRIPT_TIMEOUT in the Instagram source row. Test plan - 43 new unit tests across test_bluesky.py, test_instagram_sc.py, test_quality_nudge.py, test_youtube_yt.py - 141 total tests passing in target suite - Verified end-to-end: /last30days "Toronto resale condo market" with all 11+ sources active stored 35 new + 5 updated findings, all builder- PR-style accounts absent (organic agent voice in Instagram + TikTok results) Backward compatibility All changes are strictly additive. Optional kwargs default to None. New env vars are opt-in. Existing CLI flags untouched. Existing callers of public functions unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Trevin Chow
parent
a8e462c978
commit
44971a6aae
@@ -908,7 +908,17 @@ def main() -> int:
|
||||
suppress_web_promo=bool(external_plan or comp_plan),
|
||||
)
|
||||
_write_last_run(topic, report)
|
||||
if args.store:
|
||||
# LAST30DAYS_STORE env var = persistence default-on. Read both os.environ
|
||||
# (for shell-exported users) and config (for users who set it in
|
||||
# ~/.config/last30days/.env, which env.py loads but does not propagate
|
||||
# to os.environ). Mirrors the LAST30DAYS_DEBUG / LAST30DAYS_SKIP_PREFLIGHT
|
||||
# convention; env-var or config wins, with `--store` flag still working.
|
||||
_store_env = (
|
||||
os.environ.get("LAST30DAYS_STORE")
|
||||
or config.get("LAST30DAYS_STORE")
|
||||
or ""
|
||||
).lower()
|
||||
if args.store or _store_env in ("1", "true", "yes"):
|
||||
counts = persist_report(report)
|
||||
sys.stderr.write(
|
||||
f"[last30days] Stored {counts['new']} new, {counts['updated']} updated findings\n"
|
||||
@@ -922,6 +932,7 @@ def main() -> int:
|
||||
# degraded-YouTube failure mode (videos returned but transcripts
|
||||
# silently failed - typically a stale yt-dlp binary).
|
||||
youtube_items = report.items_by_source.get("youtube") or []
|
||||
instagram_items = report.items_by_source.get("instagram") or []
|
||||
research_results = {
|
||||
"youtube_videos_count": len(youtube_items),
|
||||
"youtube_transcripts_count": sum(
|
||||
@@ -930,6 +941,17 @@ def main() -> int:
|
||||
),
|
||||
"youtube_error": report.errors_by_source.get("youtube"),
|
||||
"x_error": report.errors_by_source.get("x"),
|
||||
# Captions-disabled videos can never produce a transcript regardless
|
||||
# of yt-dlp version; subtract them from the degraded-ratio
|
||||
# denominator so a single uploader-disabled video does not trip the
|
||||
# "stale yt-dlp" nudge.
|
||||
"youtube_captions_disabled_count": sum(
|
||||
1 for it in youtube_items if it.metadata.get("captions_disabled")
|
||||
),
|
||||
# Track Instagram returned-zero-items so quality_nudge can detect
|
||||
# the silent-failure case (SC configured but the v2 reels endpoint
|
||||
# 500'd through both the original query and the hashtag retry).
|
||||
"instagram_items_count": len(instagram_items),
|
||||
}
|
||||
quality = quality_nudge.compute_quality_score(config, research_results)
|
||||
if quality.get("nudge_text"):
|
||||
|
||||
Reference in New Issue
Block a user