Skip to content

Instantly share code, notes, and snippets.

@aldrinleal
Last active June 15, 2026 13:54
Show Gist options
  • Select an option

  • Save aldrinleal/c05e1251d1c5cb28294b40ad90ee43a3 to your computer and use it in GitHub Desktop.

Select an option

Save aldrinleal/c05e1251d1c5cb28294b40ad90ee43a3 to your computer and use it in GitHub Desktop.
MVP-790 & MVP-791 Follow-up Analysis & Ticket Status (code audit, 2026-06-15)

MVP-790 & MVP-791 — Follow-up Analysis & Ticket Status (Code Audit)

Companion to: MVP-782–789 follow-up · original Algo Signal Upgrades gist Date: 2026-06-15 (updated — MeSH floor implemented) Method: audited each ticket's acceptance criteria against sh-backend develop. Tests + the 4a floor fix added this pass.

TL;DR

Ticket Scope Status
MVP-790 Swipe L→R reduces tag weights, symmetrical with R→L, regenerates feed 🟢 Done — all 5 ACs met; tests added
MVP-791 Balanced SGC mix — 20% MeSH / 80% recent+medium 🟢 Done bar one item — ratio/balance/DS2/edge-cases + MeSH floor done & tested; only non-MeSH subtype prioritization (4b) remains, product-gated

MVP-790 — Swipe Symmetry — 🟢 DONE

Every acceptance criterion is satisfied:

AC Status Evidence
R→L swipe boosts tag weights (primary + MeSH family) → new feed more_like_this = +1.5 (engagement.py:60); MeSH-relative propagation in record_post_engagement (engagement.py:285-288)
L→R swipe reduces tag weights (primary + MeSH family) → new feed less_like_this = −1.5; same propagation path (negative delta × relative weight)
Both gestures symmetrical, both trigger feed refresh ±1.5 symmetric; both persist to user_tag_affinity, which the next PersonalizedFeedAdapter fetch reads. FE issues the visible refresh
DS2 logs both as distinct signals with affected tags listed swipe_signals (dashboard.py:1752-1792) — grouped per gesture, each with a tags list of {tag_name, delta}
New feed visibly reflects the updated weights affinity-driven; visible in DS2 feed preview + sgc_breakdown

Tests added (tests/test_engagement.py): test_swipe_gestures_are_symmetric_and_bonus_eligible — locks equal-magnitude/opposite-sign and confirms both gestures are MeSH-bonus eligible (not view-exempt). The per-tag + MeSH propagation itself is DB-bound and verified manually.

Verdict: closeable.

MVP-791 — SGC Mix — 🟢 DONE BAR ONE ITEM

The mix is solid and wired into the live feed (apply_sgc_mix at feeds_http.py:580, fed by a 4× candidate pool). After this pass only the non-MeSH subtype personalization (4b) remains, and it is product-gated.

✅ Implemented & tested

AC Status Evidence
~20% MeSH / ~80% non-MeSH apply_sgc_mix (feed_adapters.py:259)
80% non-MeSH is itself a very-recent + medium-recent mix ~40/40 split (very_recent_target = ceil(nonmesh/2))
DS2 shows SGC breakdown with actual % sgc_breakdown (dashboard.py:1826-1834, feed_adapters.py:347)
Narrow tag, scarce MeSH → fill what exists, fill rest non-MeSH, never short scarcity fallback (fills shortfall from leftovers, non-MeSH first)
Very-recent scarce → pull from medium-recent, never short same fallback path
Strong MeSH affinity → 20% is a FLOOR, not a ceiling (fixed this pass) see below

✅ 4a — MeSH floor (fixed, commit 3d358d24)

Candidates arrive score-sorted from the affinity-aware PersonalizedFeedAdapter, so MeSH a user likes already ranks high. The previous hard cap (mesh_pool[:ceil(limit*0.20)]) truncated those high-affinity users back to 20%. Replaced with a floor that keeps however many MeSH naturally land in the top limit:

natural_mesh = sum(
    1 for p in candidates[:limit]
    if post_source_map.get(int(p.id)) in MESH_POST_SOURCES
)
mesh_target = min(limit, max(1, math.ceil(limit * 0.20), natural_mesh))

High-affinity users now keep their affinity-ranked MeSH (>20%); everyone else still gets the 20% floor. Covered by test_mesh_share_is_a_floor_for_high_affinity_users (top-6 MeSH preserved) and test_mesh_floor_applies_when_affinity_is_low (pins 20% when MeSH ranks below the page).

⏸️ 4b — non-MeSH subtype prioritization (still open, product-gated)

AC Gap
Strong Pop/PopSci affinity → 80% prioritized toward preferred SGC subtype Non-MeSH is split only by recency, never by subtype (Pop vs PopSci) weighted by engagement. apply_sgc_mix has no preference input. Only implicit via upstream score ordering.

Needs a product call: does score-ordering already satisfy "prioritized toward Pop/PopSci," or is explicit per-subtype weighting (a new apply_sgc_mix parameter) required?

Tests Added

  • tests/test_sgc_mix.py — pure-function coverage of apply_sgc_mix / sgc_breakdown:
    • 20/80 ratio (floor governs when MeSH isn't front-loaded), balanced non-MeSH split, never-exceeds-limit, empty input
    • both scarcity edge cases (scarce MeSH; scarce very-recent → medium-recent)
    • exact DS2 breakdown percentages
    • MeSH floor both ways: high-affinity (>20% preserved) and low-affinity (pinned at 20%)
  • tests/test_engagement.pytest_swipe_gestures_are_symmetric_and_bonus_eligible (MVP-790)

Note: pytest's mypy-status item is red on a pre-existing, unrelated error (app/utils/analytics.py:79: posthog has no attribute "identify") — reproducible on already-committed tests (e.g. tests/test_bookmarks.py::mypy-status). Not introduced here.

Recommended Closure Actions

  1. Close MVP-790 — all ACs met, tests added.
  2. MVP-791 — mechanical mix + edge cases + MeSH floor are done and tested. Only the non-MeSH subtype prioritization (4b) remains; split it into a product-gated sub-task and close the rest.

Implementation Commits (develop)

  • 72472bf5 — test: SGC-mix (791) + swipe-symmetry (790) coverage
  • 3d358d24 — feat: make 20% MeSH share a floor not a ceiling (791 AC 4a)

References

  • app/sherpahealthy/posts/feed_adapters.pyapply_sgc_mix, sgc_breakdown
  • app/sherpahealthy/posts/feeds_http.py:520-583 — 4× candidate pool + mix wiring
  • app/admin/dashboard.py:1752-1834 — DS2 swipe_signals + sgc_breakdown
  • app/sherpahealthy/engagement.py — swipe deltas + MeSH propagation
  • tests/test_sgc_mix.py, tests/test_engagement.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment