skills/mlb-faab-sizer/SKILL.md
Computes FAAB (Free Agent Acquisition Budget) recommended and maximum bids for Yahoo fantasy baseball waiver targets. Implements the baseball-specific layering of the faab-bid-framework (positional_need_fit, role_certainty, urgency, season_pace, league-inflation calibration) and DELEGATES the game-theoretic primitives -- first-price shading and winner's-curse haircut -- to the sibling skills `auction-first-price-shading` and `auction-winners-curse-haircut`. Produces a recommended bid, a hard ceiling, a rationale with the full delegation chain, and guardrail flags. Use when the user asks "how much should I bid on X", mentions FAAB bid, waiver bid amount, blind bid, Yahoo waiver claim sizing, or when mlb-waiver-analyst needs a bid amount for an identified target.
npx skillsauth add lyndonkl/claude mlb-faab-sizerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill is a baseball-specific orchestrator. It does NOT compute auction math inline. It composes two domain-neutral sibling skills:
| Step | Who | Responsibility |
|---|---|---|
| 1 | this skill | Compute base_value from Yahoo-adjusted projection, pos fit, role certainty, urgency, season pace (with league-inflation calibration) |
| 2 | this skill | Classify target as common_value / private_value / mixed |
| 3 | auction-winners-curse-haircut | Return adjusted_valuation (Bayesian haircut for common-value) |
| 4 | this skill | Estimate N from opponent profiles |
| 5 | auction-first-price-shading | Return shaded_bid ((N-1)/N + distribution + risk adjustment) |
| 6 | this skill | Apply baseball guardrails (April 40%, speculation 20%, $1 floor, role-cert floor) |
| 7 | this skill | Emit faab_rec_bid, faab_max_bid, rationale naming both delegations |
Invariant: this skill never computes (N-1)/N or a common-value haircut directly. Any change to those primitives is made in the sibling skills.
Scenario: Roki Sasaki called up, likely Dodgers rotation spot. $100 FAAB remaining, week 4.
28 x 0.70 x 0.65 x 1.2 x 0.7 = $10.70common_value (headline prospect).auction-winners-curse-haircut with (raw=10.70, type=common_value, N=6, dispersion=60) -> adjusted_valuation = $7.39, haircut 31%.auction-first-price-shading with (true_value=7.39, N=6, dist=log-normal, risk=0.2, budget=100) -> shaded_bid = $7, shade 0.90.faab_rec_bid=$7, faab_max_bid=round($7.39 x 0.90)=$7. Rationale cites both sibling skills.Full trace in resources/methodology.md and resources/template.md.
FAAB Sizing Progress:
- [ ] Step 1: Collect input signals and budget state
- [ ] Step 2: Compute base_value (baseball layering)
- [ ] Step 3: Classify value_type
- [ ] Step 4: Invoke auction-winners-curse-haircut -> adjusted_valuation
- [ ] Step 5: Estimate N from opponent profiles
- [ ] Step 6: Invoke auction-first-price-shading -> shaded_bid
- [ ] Step 7: Apply baseball guardrails
- [ ] Step 8: Emit signal + rationale with delegation trace
Step 1: Collect inputs (ask caller if missing):
acquisition_value ($, 1-100 scale) -- from mlb-player-analyzerpositional_need_fit (0-100) -- from mlb-waiver-analystrole_certainty (0-100) -- from mlb-player-analyzerStep 2: Compute base_value (baseball-specific layering):
base_value = acquisition_value
x (positional_need_fit / 100)
x (role_certainty / 100)
x urgency_multiplier [0.7 - 1.4]
x season_pace_multiplier [0.6 - 1.4 after inflation calib]
Urgency: 1.4 (closer loses job / prospect called up); 1.2 (new opportunity); 1.0 (steady); 0.8 (wave); 0.7 (speculation).
Pace base: 0.6 (Apr wk 1-4), 1.0 (May-Jun), 1.2 (Jul-Aug), 1.4/0.5 (Sept contending/eliminated). Then multiply by league_inflation_ratio from tracker/faab-log.md (see methodology.md). Min 5 valid rows; else skip calibration and flag low_calibration_data.
Step 3: Classify value_type:
common_value: headline prospect, named closer, star off IL (same info for all teams)private_value: handcuff, platoon fit, punt-category-specific (only we weigh this way)mixed: record common/private weightDefault to common_value when uncertain (conservative; triggers haircut).
Step 4: Invoke auction-winners-curse-haircut — keyed off CONTESTED bidders, not the full field:
inputs = { raw_valuation: base_value, value_type, n_informed_bidders: n_contesters,
signal_dispersion: 40 (default) }
n_contesters = rivals realistically expected to bid on THIS specific target (see Step 5). Do NOT pass the full plausible field here. The winner's-curse haircut (Step 4) and the first-price shade (Step 6) MUST key off different counts — otherwise one "many bidders" signal is counted twice and we systematically under-bid contested closers/call-ups to ~58% of true value (audit 2026-06-02, the verified mlb-faab-sizer double-count). If n_contesters <= 1 the target is effectively uncontested → the haircut short-circuits to 0 (treat as private-value). Consume adjusted_valuation; preserve classification_rationale. Dispersion defaults: 60 prospects, 30 established, 40 otherwise.
Step 5: Estimate the TWO bidder counts from opponent profiles (they are deliberately different numbers; they converge only when a target is genuinely hotly contested):
n_contesters (drives Step 4 haircut) — rivals with positional_need > 50 AND faab > 20% original AND activity >= moderate AND a concrete reason to want THIS player. In our deflated market (modal winning bid $1-2) this is typically 1-2, occasionally 3-4 for a confirmed closer change. Clamp [0, 6].N_field (drives Step 6 shading) — the broader set who could plausibly bid. Clamp [1, 8]. Defaults: common superstar 6, role-player 3, private 1-2.Step 6: Invoke auction-first-price-shading — keyed off the full field:
inputs = { true_value: adjusted_valuation, n_bidders_estimate: N_field,
value_distribution: "log-normal" (MLB default),
risk_aversion: 0.2 (bump to 0.4 for contending September),
budget_remaining: faab_remaining }
shaded_bid becomes pre-guardrail faab_rec_bid. Set faab_max_bid = round(adjusted_valuation x 0.90).
Step 7: Apply baseball guardrails (see below). Never silently violate.
Step 8: Emit via mlb-signal-emitter. User-facing rationale MUST name both sibling skills by purpose. Validate with rubric. Minimum 3.5.
1. Hot common-value call-up (early season): N=5-7, pace 0.6-0.7, haircut ~25-30%, shade ~0.80-0.85. Typical $5-$12 rec.
2. Private-value handcuff: N=1-2, haircut=0 (short-circuit), shade 0.0-0.5. Typical $1-$3 rec.
3. Closer change (mid-season, common-value): N=5-8, urgency 1.4, haircut ~25%, shade ~0.83. Typical $10-$30 rec.
4. September contender stretch target: pace 1.4, risk_aversion bumped to 0.4, shade ~0.88-0.92. Can reach 40-60% of remaining FAAB.
faab_max_bid ≤ 40% of FAAB remaining. Flag april_40pct_cap_triggered.situation=speculation or role_certainty<30, cap at 20%. Flag speculation_20pct_cap_triggered.shaded_bid rounds to $0 but positional_need_fit >= 30, bid $1 (rolling-list tiebreak). Otherwise bid $0 and flag zero_bid_preservation.role_certainty < 20, force faab_rec_bid = $0. Flag role_certainty_floor.regression_index < -30, cut faab_rec_bid by 30%. Flag regression_luck_discount.variant_divergence_applied.budget_floor_near_zero.mlb-decision-logger (including $0 bids).Do NOT duplicate sibling caps: the 0.9 x true_value ceiling is enforced by auction-first-price-shading; the 35% haircut cap is enforced by auction-winners-curse-haircut. Trust them.
Pipeline:
base_value = acq_value x (pos_fit/100) x (role_cert/100) x urgency x pace_calibrated
adjusted_valuation = auction-winners-curse-haircut(
raw_valuation=base_value, value_type, n_informed_bidders=N, signal_dispersion)
shaded_bid = auction-first-price-shading(
true_value=adjusted_valuation, n_bidders_estimate=N,
value_distribution="log-normal", risk_aversion=0.2, budget_remaining)
faab_rec_bid = round(shaded_bid) # then baseball guardrails
faab_max_bid = round(adjusted_valuation x 0.90)
Inputs required: acquisition_value, positional_need_fit, role_certainty, FAAB remaining, week, situation label, regression_index (optional).
Outputs: faab_rec_bid, faab_max_bid, value_type, N, adjusted_valuation, shaded_bid, multipliers, guardrail flags, user-facing rationale.
Sibling skills:
@skills/auction-first-price-shading/ -- (N-1)/N + distribution + risk-aversion@skills/auction-winners-curse-haircut/ -- Bayesian common-value haircutKey resources:
testing
Cluster a conference's event records into a small set of coarse themes with finer sub-clusters, an explicit outlier bucket, and soft (multi-membership) affinities — using the hybrid embed-then-label pipeline (embed abstracts, reduce, density-cluster, then LLM-label the clusters) when embedding libraries are available, and an LLM-reasoned hierarchical fallback when they are not. Embeddings do the grouping; the LLM only names the groups. Conference-agnostic. Use when turning structured event records into a navigable theme map for preference elicitation and scheduling, when you need 6-8 reasonable themes rather than 20 muddy ones, or when overlapping talks must belong to more than one theme. Trigger keywords - theme clustering, cluster talks, embed then label, soft membership, outlier talks, conference themes, topic map.
development
Build a personal conference schedule as a constraint-optimization problem — hard constraints (no time overlap, room-to-room travel time, capacity/registration, the attendee's own must-attends and blackouts) plus a user-owned weighted objective trading interest against breadth, pacing (maximize contiguous free time), and serendipity. Surfaces unbreakable conflicts (two high-value overlapping talks the model cannot rank) as decisions for the human rather than silently picking, and reports what each choice traded away. Conference-agnostic. Use to turn a preference profile plus a theme map into a day-by-day plan, to resolve overlapping sessions, or to balance a packed vs paced schedule. Trigger keywords - schedule optimization, conference schedule, constraint optimization, overlapping talks, contiguous free time, conflict surfacing, packed vs paced.
development
Parse a heterogeneous conference program (markdown, HTML, PDF-derived text, or JSON) into normalized event records with per-field confidence scores and independent classification axes (topic, depth, format, prerequisites, recorded, capacity). Detects the program's format before extracting, treats every inferred field as uncertain (present vs inferred vs missing), and flags thin or missing abstracts so downstream enrichment can target them. Conference-agnostic. Use when ingesting a conference or event schedule into a structured store, normalizing a talk/session list, or extracting per-session metadata with calibrated confidence. Trigger keywords - program ingestion, parse schedule, session extraction, event records, conference program, talk metadata, per-field confidence.
development
Build a personalized preference profile from a small number of well-chosen, cluster-grounded questions instead of a long survey. Represents the person's interests as an uncertainty region over the theme map, picks the single highest-information-gain choice-based question (contrasting real talks from different clusters), balances exploiting known interests against exploring uncertain ones, deliberately injects outlier probes to fight selection bias, and stops as soon as the schedule would be stable. Also elicits the user-owned objective weights and hard constraints. Interactive — runs where it can actually ask the person. Conference-agnostic. Use to turn a theme map into a preference profile, to decide what to ask a conference attendee, or to elicit scheduling priorities. Trigger keywords - preference elicitation, ask few questions, information gain, choice-based questions, selection bias probe, objective weights, attendee preferences.