feat: league category posture in trade builder + finder#99
Merged
Conversation
Both trade tools now know where the *other* team stands, not just the manager's own weaknesses — so counters explain why an opponent wants your guy, and the finder becomes matchmaking (which owners need what you'd send). - category_ranks now exposes compute_category_matrix: the full league matrix (per-team ranks + role counts), the reusable primitive. compute_category_ranks is a thin backward-compatible wrapper over it. - Role counts come free from roster_items[].position (raw Fantrax eligibility) + player_type — no new data, no migration. SP/RP token-matched so "SP,RP" counts both. - posture() is a pure, tested classifier (punt|need|strong|mid): weak rank + <=1 contributor = punt (deliberate zero, e.g. 1 RP and last in SV); weak + depth = need. Never persisted, so the heuristic tunes without a cache flush. - _run_category_ranks_compute writes both the legacy category_ranks blob and the new category_matrix row from one compute (no drift); widget/history untouched. - build_trade_context adds the opponent's posture line; build_finder_context adds rival postures for candidate owners. Prompt-facing view is a tiny sliced digest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
railway-app
Bot
temporarily deployed
to
dynastyops-secordlabs / dynastyos-pr-99
July 22, 2026 16:38
Destroyed
asecord92
added a commit
that referenced
this pull request
Jul 22, 2026
The posture PR (#99) wrote a new category_matrix row to dashboard_cache, but the table's widget CHECK constraint didn't whitelist it — every compute raised 23514 and, because both rows were upserted together, took the essential category_ranks + history write down with it. Category ranks silently stopped updating (and start/sit/news lost their weak-category context line). - Migration 20260722_category_matrix_widget.sql adds category_matrix to the allowed widget list (apply manually in Supabase SQL editor). - Split _run_category_ranks_compute into two writes: category_ranks + history land first and unconditionally; category_matrix is a separate best-effort upsert, so a matrix failure can never block the essential ranks again. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The trade tools only knew my weaknesses. Now they know where the other team stands, so:
Came out of a design conversation. The insight: ranks are volatile, roster construction is intent. A rank of "11th in SV" reads identically whether you're punting or desperate — so we pair the rank with a role count to disambiguate. My own team (1 closer, last in saves) correctly reads punt, not "go get a closer."
How
category_ranksnow exposescompute_category_matrix— the full league matrix (per-team ranks + role counts).compute_category_ranksis a thin backward-compatible wrapper over it.roster_items[].position(raw Fantrax eligibility) +player_type. No new data, no migration."SP,RP"is token-matched so multi-eligible arms count for both.posture()is a pure, tested classifier (punt | need | strong | mid): weak rank + ≤1 contributor = punt; weak + real depth = need; top-third = strong. Never persisted — the heuristic tunes without a cache flush._run_category_ranks_computewrites both the legacycategory_ranksblob and the newcategory_matrixrow from one compute (no drift). Widget + rank history untouched.Notes / lean-by-design
category_matrixyet → posture is silently omitted until their next sync/compute.Test
posture/team_posture_summary/_role_counts/my_ranks_from_matrixexercised directly — punt vs. need behaves (incl. the 1-closer case).ruffclean; engine +api.mainimport smoke pass.🤖 Generated with Claude Code