mlb-signal-emitter

$npx mdskill add lyndonkl/claude/mlb-signal-emitter

Validate and persist MLB signals with strict schema enforcement.

  • Ensures signal files meet required frontmatter and numeric range standards.
  • Integrates with mlb-decision-logger for failure routing.
  • Routes invalid data to the decision logger instead of persisting.
  • Generates standardized files in the signals directory.

SKILL.md

.github/skills/mlb-signal-emitterView on GitHub ↗
---
name: mlb-signal-emitter
description: Validates and persists signal files to the yahoo-mlb signals directory. Every MLB skill calls this skill before writing a signal. Enforces the signal-framework.md schema -- required YAML frontmatter fields (type, date, emitted_by, confidence, source_urls), range-checks numeric signals (0-100 unipolar, -100 to +100 bipolar), verifies variant_synthesis metadata, and enforces file naming. On validation failure, does not persist and routes a failure entry to mlb-decision-logger. Use when an agent or skill needs to emit a signal, validate a signal file, write to signals/YYYY-MM-DD-<type>.md, or check signal frontmatter. Triggers: "emit signal", "validate signal", "write signal file", "signal frontmatter".
---
# MLB Signal Emitter

## Table of Contents
- [Example](#example)
- [Workflow](#workflow)
- [Common Patterns](#common-patterns)
- [Guardrails](#guardrails)
- [Quick Reference](#quick-reference)

## Example

**Scenario**: `mlb-player-analyzer` has computed a `daily_quality` signal for Junior Caminero on 2026-04-17 and wants to persist it.

**Inputs passed to this skill**:
- `type: player`
- `date: 2026-04-17`
- `emitted_by: mlb-player-analyzer`
- `variant_synthesis: true`, `variants_fired: [advocate, critic]`
- Body contains: `form_score: 68`, `matchup_score: 74`, `opportunity_score: 62`, `daily_quality: 69`, `regression_index: +18`, `confidence: 0.78`
- `source_urls: [baseballsavant..., fangraphs..., mlb.com/gameday...]`

**Validation pass** (what this skill checks):

| Check | Result |
|---|---|
| YAML frontmatter parses | PASS |
| `type` is in allowed enum | PASS (`player`) |
| `date` is ISO YYYY-MM-DD | PASS |
| `emitted_by` present | PASS |
| `confidence` in [0.0, 1.0] | PASS (0.78) |
| `source_urls` is non-empty list | PASS (3 URLs) |
| `variant_synthesis: true` implies `variants_fired` has >= 1 | PASS (2 fired) |
| All numeric signals in declared range | PASS (all 0-100 signals clamped; regression_index in +-100) |
| File path matches `signals/YYYY-MM-DD-<type>.md` convention | PASS |

**Action**: Write to `~/Documents/Projects/yahoo-mlb/signals/2026-04-17-player-caminero.md` and return the absolute path.

**Failure scenario**: If `confidence: 1.4` had been passed, validation fails. The skill does NOT write the file. It calls `mlb-decision-logger` with a failure entry: `kind: signal_validation_failure`, `signal_type: player`, `reason: confidence out of range (1.4 not in [0.0, 1.0])`, `emitter: mlb-player-analyzer`, and returns an error to the calling agent.

## Workflow

Copy this checklist and track progress:

```
Signal Emission Progress:
- [ ] Step 1: Receive signal payload from upstream skill/agent
- [ ] Step 2: Validate YAML frontmatter (required fields)
- [ ] Step 3: Range-check all numeric signals
- [ ] Step 4: Validate variant synthesis metadata
- [ ] Step 5: Determine and validate file path
- [ ] Step 6: Write file OR log validation failure
```

**Step 1: Receive signal payload**

The caller hands in three things: (1) YAML frontmatter key-value pairs, (2) signal body (markdown tables), (3) intent (e.g., "this is a final synthesized signal" vs. "this is an intermediate variant dump"). See [resources/template.md](resources/template.md) for the canonical input shape.

- [ ] Frontmatter fields collected
- [ ] Body (markdown tables) supplied
- [ ] Intent known: final vs. variant-intermediate

**Step 2: Validate YAML frontmatter**

Confirm all required keys are present and well-typed. See [resources/methodology.md](resources/methodology.md#required-frontmatter-fields) for the full list.

- [ ] `type` present and in the allowed enum (lineup, waivers, streaming, trade, category-plan, playoff-push, player, matchup, regression, two-start, closer, faab, cat-state)
- [ ] `date` present and formatted `YYYY-MM-DD`
- [ ] `emitted_by` present and references a known skill or agent
- [ ] `confidence` present as a float in [0.0, 1.0]
- [ ] `source_urls` present as a non-empty list of URLs

**Step 3: Range-check numeric signals**

Every numeric signal in the body must fall inside its declared range. See [resources/methodology.md](resources/methodology.md#range-check-rules) for the per-signal range table (it mirrors signal-framework.md).

- [ ] Unipolar signals (form_score, matchup_score, opportunity_score, daily_quality, qs_probability, streamability_score, role_certainty, cat_pressure, playoff_matchup_quality, etc.) in [0, 100]
- [ ] Bipolar signals (regression_index, positional_flex_delta) in [-100, +100]
- [ ] Integer signals (playoff_games) >= 0
- [ ] Dollar signals (acquisition_value, faab_max_bid, faab_rec_bid) >= 0
- [ ] Enum signals (cat_position, verdict) inside their declared allowed sets

**Step 4: Validate variant synthesis metadata**

If this is a synthesized final signal, it must declare which variants produced it.

- [ ] If `variant_synthesis: true`, `variants_fired` is a list with >= 1 entry
- [ ] If `variant_synthesis: true`, `synthesis_confidence` is present and in [0.0, 1.0]
- [ ] If `variant_synthesis: false`, the file is an intermediate variant dump; filename must include the variant suffix (see Step 5)
- [ ] `red_team_findings` (if present) is a list of objects with `severity`, `likelihood`, `score`, `note` fields

**Step 5: Determine and validate file path**

The canonical path is `~/Documents/Projects/yahoo-mlb/signals/YYYY-MM-DD-<type>.md`. For an intermediate variant dump, use `YYYY-MM-DD-<type>-<variant>.md`. For per-player or per-game files, an optional identifier suffix is allowed: `YYYY-MM-DD-<type>-<identifier>.md`.

- [ ] Compute path from `date` and `type` in frontmatter
- [ ] Check that a signal of this type+date does not already exist unless the caller explicitly passed `overwrite: true`
- [ ] Ensure the parent directory exists (create if missing)
- [ ] Reject paths that escape the `signals/` directory

**Step 6: Write file OR log validation failure**

If all checks pass: write the file, return the absolute path. If any check fails: do NOT write, call `mlb-decision-logger` with a structured failure entry, return an error object to the caller. See [resources/methodology.md](resources/methodology.md#handling-validation-failures) for the failure log schema.

- [ ] On pass: write file, return absolute path
- [ ] On fail: build failure object (reason, field, expected, actual), send to `mlb-decision-logger`, return error

## Common Patterns

**Pattern 1: Per-player daily signal (`type: player`)**
- Filename: `YYYY-MM-DD-player-<lastname>.md` (e.g., `2026-04-17-player-caminero.md`)
- Required numeric signals in body: `daily_quality`, plus the three components (`form_score`, `matchup_score`, `opportunity_score`)
- Always a final synthesized signal when emitted by `mlb-player-analyzer` -- so `variant_synthesis: true` and `variants_fired: [advocate, critic]`
- Source URLs must include Baseball Savant, FanGraphs, and MLB.com (confirmed lineup)

**Pattern 2: Daily lineup roll-up (`type: lineup`)**
- Filename: `YYYY-MM-DD-lineup.md`
- Body references, by name, the per-player signal files it consumed (provenance chain)
- `synthesis_confidence` reflects agreement between the advocate (bat-everyone) and critic (sit-risky) variants
- Red-team findings typically flag weather, role uncertainty, or fragile platoon calls

**Pattern 3: Intermediate variant dump (variant suffix in filename)**
- Filename: `YYYY-MM-DD-<type>-advocate.md` or `YYYY-MM-DD-<type>-critic.md`
- `variant_synthesis: false` (this IS a variant, not a synthesis)
- `emitted_by` names the agent and variant (e.g., `mlb-lineup-optimizer/advocate`)
- The synthesizing agent reads these two intermediate files, produces the final synthesized signal, then emits with `variant_synthesis: true`

**Pattern 4: Low-confidence graceful degrade**
- When a web search fails, the upstream skill should still emit a signal but with `confidence <= 0.3` and a `red_team_findings` entry flagging the missing data source
- This skill does NOT reject low-confidence signals -- low confidence is legitimate. It only rejects out-of-range or missing fields.
- Flag in body: "Could not verify opposing pitcher; using prior-start proxy."

## Guardrails

1. **Never silently drop a signal.** If validation fails, the failure must be logged via `mlb-decision-logger` so the calibration review can see what was rejected and why. A signal that never gets written AND never gets logged is invisible to the team.

2. **Do not re-derive signal values.** This skill is a validator and file-writer only. It never computes `daily_quality` or any other signal itself. If an upstream skill passes in a half-computed signal, reject it rather than filling in the blanks.

3. **Reject unknown `type` values.** The enum in signal-framework.md is the authoritative list. If a caller passes `type: vibe-check`, reject and log. Adding a new signal type requires updating signal-framework.md first, then this skill's validator.

4. **Range checks are hard limits.** A `form_score` of 105 is not "close enough" -- it indicates a bug upstream (probably forgot to normalize). Reject and log. Do NOT clamp-and-accept.

5. **`confidence` is required, not optional.** Even a perfectly-computed signal with three source URLs must carry a confidence float. A missing confidence is a validator failure, not a warning.

6. **`source_urls` must be a non-empty list.** Per CLAUDE.md rule 1 ("Web-search everything"), every factual signal is backed by a live source. An empty `source_urls` list means the signal was not grounded -- reject and log.

7. **Variant synthesis claims must be provable.** If `variant_synthesis: true` but `variants_fired` is empty or missing, that is a lie about the team's process. Reject and log.

8. **Do not overwrite without explicit consent.** If a signal already exists at the target path, refuse to overwrite unless the caller passes `overwrite: true`. This prevents losing an earlier morning's signal when a mid-day re-run happens.

## Quick Reference

**Required frontmatter fields (always):**
- `type` (enum)
- `date` (YYYY-MM-DD)
- `emitted_by` (string)
- `confidence` (float 0.0-1.0)
- `source_urls` (non-empty list)

**Required when `variant_synthesis: true`:**
- `variants_fired` (list, >= 1)
- `synthesis_confidence` (float 0.0-1.0)

**File path conventions:**
- Final synthesized: `signals/YYYY-MM-DD-<type>.md`
- With identifier: `signals/YYYY-MM-DD-<type>-<id>.md`
- Intermediate variant: `signals/YYYY-MM-DD-<type>-<variant>.md`

**Signal ranges (see [resources/methodology.md](resources/methodology.md#range-check-rules) for the full table):**
- Unipolar (0-100): form_score, matchup_score, opportunity_score, daily_quality, qs_probability, k_ceiling, era_whip_risk, streamability_score, role_certainty, save_role_certainty, cat_pressure, cat_reachability, cat_punt_score, positional_need_fit, opp_sp_quality, park_hitter_factor, park_pitcher_factor, weather_risk, bullpen_state, playoff_matchup_quality, holding_value, obp_contribution, sb_opportunity
- Bipolar (-100 to +100): regression_index, positional_flex_delta
- Dollar (>= 0): acquisition_value, faab_max_bid, faab_rec_bid, trade_value_delta
- Integer (>= 0): playoff_games
- Enum: cat_position (winning|tied|losing), verdict (accept|counter|reject)

**On validation failure:**
1. Do NOT write the signal file.
2. Build failure entry: `{kind: signal_validation_failure, signal_type, reason, field, expected, actual, emitter, timestamp}`.
3. Call `mlb-decision-logger` with the failure entry.
4. Return an error object to the caller.

**Key resources:**
- **[resources/template.md](resources/template.md)**: Canonical signal file template with every required frontmatter field and a fully-populated example body
- **[resources/methodology.md](resources/methodology.md)**: Validation rules -- required fields, range checks, variant-synthesis checks, path conventions, failure handling
- **[resources/evaluators/rubric_mlb_signal_emitter.json](resources/evaluators/rubric_mlb_signal_emitter.json)**: 8 criteria for evaluating the emitter's behavior

**Inputs required:**
- Frontmatter key-value pairs from caller
- Signal body (markdown tables)
- `overwrite` flag (default false)

**Outputs produced:**
- On success: absolute file path of the written signal
- On failure: error object; a failure entry appended to `tracker/decisions-log.md` via `mlb-decision-logger`

More from lyndonkl/claude

SkillDescription
abstraction-concrete-examplesBuilds structured abstraction ladders that translate high-level principles into concrete, actionable examples across 3-5 levels. Bridges communication gaps, reveals hidden assumptions, and tests whether abstract ideas work in practice. Use when explaining concepts at different expertise levels, moving between abstract principles and concrete implementation, identifying edge cases by testing ideas against scenarios, designing layered documentation, decomposing complex problems into actionable steps, or bridging strategy-execution gaps.
academic-letter-architectGuides the creation of evidence-based academic recommendation letters, reference letters, and award nominations that combine concrete examples, meaningful comparisons, and genuine enthusiasm. Use when writing recommendation letters for students, postdocs, or colleagues, or when user mentions recommendation letter, reference, nomination, letter of support, endorsement, or needs help with strong advocacy and comparative statements.
adr-architectureDocuments significant architectural and technical decisions with full context, alternatives considered, trade-offs analyzed, and consequences understood. Creates a decision trail that helps teams understand why decisions were made. Use when choosing between technology options, making infrastructure decisions, establishing standards, migrating systems, or when user mentions ADR, architecture decision, technical decision record, or decision documentation.
adverse-selection-priorProduces a Bayesian prior probability that an offered transaction is +EV for the recipient, given that the counterparty chose to propose it. Applies Akerlof market-for-lemons logic -- if they offered it, they believe it is +EV for them, so the prior that it is +EV for us is materially below 50%. Reusable across trade evaluation, waiver drops (another team dropping a player is also adverse selection), job-offer analysis, M&A, and any "someone offered me this" situation. Use when you receive an unsolicited trade/offer/proposal, analyzing incoming trade prior, evaluating why a counterparty proposed a deal, or when user mentions adverse selection, market for lemons, why did they offer this, incoming trade prior, they proposed it, Bayesian adjustment on received offer.
alignment-values-north-starCreates actionable alignment frameworks that give teams a shared North Star (direction), values (guardrails), and decision tenets (behavioral standards). Enables autonomous decision-making while maintaining organizational coherence. Use when starting new teams, scaling organizations, defining culture, establishing product vision, resolving misalignment, creating strategic clarity, or when user mentions North Star, team values, mission, principles, guardrails, decision framework, or cultural alignment.
analogy-weight-checkFor every analogy in a substacker draft, verifies it carries mechanical weight — the analogy does real work explaining the mechanism, not merely decorates it. Cross-references analogy-catalog.md for novelty (is this analogy reused from a prior post?) and domain fit (biology > organizational > sports preferred; physics/military disfavored). Use whenever an analogy appears in the draft. Trigger keywords: analogy weight, decorative, mechanical weight, reused analogy, catalog check, metaphor check.
answer-uncomfortable-questionTakes one strategic question about substacker ("should we launch paid?", "is this section dead?", "are we writing for the wrong audience?") and produces the mandatory evidence + reasoning + downside triad plus a recommendation. Used 3 times per Growth Strategist review. Trigger keywords: uncomfortable question, strategic question, evidence reasoning downside, triad.
attribute-performanceFor each substacker post that materially over- or under-performs the rolling baseline (|z| ≥ 1.0), produces a plain-English attribution paragraph with calibrated confidence (high / medium / low / unexplained). Considers subject-line effect, topic zeitgeist, external share, day-of-week, length effect, and audience-notes signals. Labels unexplained outliers explicitly rather than fabricating a story. Use after compute-baseline when outlier posts exist. Trigger keywords: attribution, why did this post work, outlier explanation, performance analysis.
auction-first-price-shadingComputes the optimal shaded bid for a first-price sealed-bid auction given a true private value, an estimate of the number of competing bidders N, and a value-distribution assumption. Implements the `(N-1)/N` equilibrium shading rule for uniform private values, adjusts for log-normal or empirical value distributions, layers a risk-aversion adjustment, and caps output against the bidder's remaining budget. Domain-neutral auction theory reusable across fantasy sports (baseball FAAB, NBA/NHL waiver auctions), prediction-market limit sizing, sealed procurement bids, and any blind-bid context. Use when user mentions "first-price auction bid", "sealed bid shading", "(N-1)/N", "FAAB bid amount", "auction shading", "optimal bid first-price", "bid for sealed-bid", "blind bid sizing", or when downstream logic needs a principled shade factor rather than an ad-hoc heuristic.
auction-winners-curse-haircutApplies a Bayesian haircut to a bid valuation for common-value auctions where winning is itself evidence the bidder over-estimated. Takes a raw valuation, a value-type classification (common_value / private_value / mixed), the number of informed bidders N, and a signal-dispersion estimate, and returns an adjusted valuation. Domain-neutral and reusable across fantasy FAAB, prediction markets, M&A bids, ad-auction budgets, and any generic bidding context. Use when user mentions "winner's curse", "common value auction", "valuation haircut", "adverse valuation", "Bayesian bid adjustment", or "over-paying in auction".