nsaroiu commited on
Commit
2fd2eab
·
verified ·
1 Parent(s): 6e1038e

Deploy a9d45ca

Browse files
server/deckbuilder.py CHANGED
@@ -74,6 +74,14 @@ class DeckCard:
74
  category: str
75
  oracle_text: str
76
  locked: bool = False # kept from a previous completion at the user's request
 
 
 
 
 
 
 
 
77
  # Per-face power/toughness, loyalty, or defense ("4/3", "Loyalty 3", None), see server/card_stats.py.
78
  stats: list[str | None] = field(default_factory=list)
79
  # Cheapest paper printing: {"usd": 0.25, "set": "M21", "finish": "foil"}, see server/card_prices.py.
@@ -291,6 +299,7 @@ class DeckBuilder:
291
  type_line=card.type_line, mana_cost=card.mana_cost, cmc=card.cmc,
292
  category=category_of(card.type_line), oracle_text=card.oracle_text,
293
  stats=self.card_stats.get(card.oracle_id, []), price=self.prices.get(card.oracle_id),
 
294
  )
295
 
296
  def _basic_card(self, name: str, quantity: int, source: str) -> DeckCard:
 
74
  category: str
75
  oracle_text: str
76
  locked: bool = False # kept from a previous completion at the user's request
77
+ # Real-deck-frequency classification ("staple" | "mid" | "long_tail"),
78
+ # None for basics (outside the tokenizer vocab, so untiered). Distinct
79
+ # from `source`: the synergy phase runs unrestricted and routinely
80
+ # picks real staples (Sol Ring, Command Tower) on their own merit, so
81
+ # a card can be source="synergy" and tier="staple" at once -- without
82
+ # this field the frontend had no way to show that, and a staple could
83
+ # read as "just a synergy pick" with nothing marking it as universal.
84
+ tier: str | None = None
85
  # Per-face power/toughness, loyalty, or defense ("4/3", "Loyalty 3", None), see server/card_stats.py.
86
  stats: list[str | None] = field(default_factory=list)
87
  # Cheapest paper printing: {"usd": 0.25, "set": "M21", "finish": "foil"}, see server/card_prices.py.
 
299
  type_line=card.type_line, mana_cost=card.mana_cost, cmc=card.cmc,
300
  category=category_of(card.type_line), oracle_text=card.oracle_text,
301
  stats=self.card_stats.get(card.oracle_id, []), price=self.prices.get(card.oracle_id),
302
+ tier=self.tiers.get(self.tok.token_to_id[self.tok.oracle_id_to_token[card.oracle_id]]),
303
  )
304
 
305
  def _basic_card(self, name: str, quantity: int, source: str) -> DeckCard:
web/src/api.ts CHANGED
@@ -2,10 +2,17 @@
2
 
3
  export type CardSource = 'input' | 'synergy' | 'staple' | 'basic'
4
 
 
 
 
 
 
 
5
  export interface DeckCard {
6
  name: string
7
  quantity: number
8
  source: CardSource
 
9
  score: number | null
10
  type_line: string
11
  mana_cost: string
 
2
 
3
  export type CardSource = 'input' | 'synergy' | 'staple' | 'basic'
4
 
5
+ /** Real-deck-frequency classification, independent of `source` -- the
6
+ * synergy phase is unrestricted and routinely picks real staples on their
7
+ * own merit, so a card can be source: 'synergy' and tier: 'staple' at
8
+ * once. null for basics (outside the tokenizer vocab, so untiered). */
9
+ export type CardTier = 'staple' | 'mid' | 'long_tail'
10
+
11
  export interface DeckCard {
12
  name: string
13
  quantity: number
14
  source: CardSource
15
+ tier: CardTier | null
16
  score: number | null
17
  type_line: string
18
  mana_cost: string
web/src/components/DeckView.tsx CHANGED
@@ -132,9 +132,18 @@ function CardRow({
132
  const adjustable = !isCommander && isAdjustable(card)
133
  const isBanned = adjustable && banned.has(card.name)
134
  const locked = adjustable && !isBanned && lockedNames.has(card.name)
135
- const title = card.source === 'input' || isCommander
136
- ? SOURCE_LABELS.input
137
- : card.score != null ? `${SOURCE_LABELS[card.source]} · model score ${card.score.toFixed(3)}` : SOURCE_LABELS[card.source]
 
 
 
 
 
 
 
 
 
138
  const classes = [
139
  'card-row',
140
  `source-${isCommander ? 'commander' : card.source}`,
@@ -171,6 +180,7 @@ function CardRow({
171
  </span>
172
  )}
173
  {isCommander && <span className="tag">Commander</span>}
 
174
  <ManaCost cost={card.mana_cost} />
175
  {/* Fixed-width, right-aligned last column so prices line up down each
176
  group; an empty cell keeps the column when a card has no price. */}
 
132
  const adjustable = !isCommander && isAdjustable(card)
133
  const isBanned = adjustable && banned.has(card.name)
134
  const locked = adjustable && !isBanned && lockedNames.has(card.name)
135
+ // A card picked by the synergy phase can still be a real staple by
136
+ // real-deck frequency -- the synergy phase is unrestricted and often
137
+ // picks staples (Sol Ring, Command Tower) on their own merit. Call that
138
+ // out specifically: it's the one case where `source` alone would read
139
+ // as "just a synergy pick" when the card is actually universal.
140
+ const isUnlabeledStaple = card.source === 'synergy' && card.tier === 'staple'
141
+ const sourceLabel = card.source === 'input' || isCommander ? SOURCE_LABELS.input : SOURCE_LABELS[card.source]
142
+ const title = [
143
+ sourceLabel,
144
+ isUnlabeledStaple && 'also a staple',
145
+ !isCommander && card.score != null && `model score ${card.score.toFixed(3)}`,
146
+ ].filter(Boolean).join(' · ')
147
  const classes = [
148
  'card-row',
149
  `source-${isCommander ? 'commander' : card.source}`,
 
180
  </span>
181
  )}
182
  {isCommander && <span className="tag">Commander</span>}
183
+ {isUnlabeledStaple && <span className="tag tag-staple" title="Also a staple by real-deck frequency">Staple</span>}
184
  <ManaCost cost={card.mana_cost} />
185
  {/* Fixed-width, right-aligned last column so prices line up down each
186
  group; an empty cell keeps the column when a card has no price. */}
web/src/index.css CHANGED
@@ -740,6 +740,15 @@ textarea {
740
  color: var(--warn-text);
741
  }
742
 
 
 
 
 
 
 
 
 
 
743
  /* ---------- mana symbols ---------- */
744
 
745
  .mana-cost {
 
740
  color: var(--warn-text);
741
  }
742
 
743
+ /* Outlined, not filled like .tag/.tag-warn -- this flags a secondary fact
744
+ about the card (it's also a staple) alongside its primary source dot,
745
+ not a replacement for it. */
746
+ .tag-staple {
747
+ background: transparent;
748
+ border: 1px solid var(--src-staple);
749
+ color: var(--src-staple);
750
+ }
751
+
752
  /* ---------- mana symbols ---------- */
753
 
754
  .mana-cost {