skills/mlb-signal-emitter/SKILL.md
--- 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
npx skillsauth add lyndonkl/claude skills/mlb-signal-emitterInstall 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.
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: playerdate: 2026-04-17emitted_by: mlb-player-analyzervariant_synthesis: true, variants_fired: [advocate, critic]form_score: 68, matchup_score: 74, opportunity_score: 62, daily_quality: 69, regression_index: +18, confidence: 0.78source_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 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.
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 for the canonical input shape.
Step 2: Validate YAML frontmatter
Confirm all required keys are present and well-typed. See resources/methodology.md 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-DDemitted_by present and references a known skill or agentconfidence present as a float in [0.0, 1.0]source_urls present as a non-empty list of URLsStep 3: Range-check numeric signals
Every numeric signal in the body must fall inside its declared range. See resources/methodology.md for the per-signal range table (it mirrors signal-framework.md).
Step 4: Validate variant synthesis metadata
If this is a synthesized final signal, it must declare which variants produced it.
variant_synthesis: true, variants_fired is a list with >= 1 entryvariant_synthesis: true, synthesis_confidence is present and in [0.0, 1.0]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 fieldsStep 5: Determine and validate file path
The canonical path is 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.
date and type in frontmatteroverwrite: truesignals/ directoryStep 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 for the failure log schema.
mlb-decision-logger, return errorPattern 1: Per-player daily signal (type: player)
YYYY-MM-DD-player-<lastname>.md (e.g., 2026-04-17-player-caminero.md)daily_quality, plus the three components (form_score, matchup_score, opportunity_score)mlb-player-analyzer -- so variant_synthesis: true and variants_fired: [advocate, critic]Pattern 2: Daily lineup roll-up (type: lineup)
YYYY-MM-DD-lineup.mdsynthesis_confidence reflects agreement between the advocate (bat-everyone) and critic (sit-risky) variantsPattern 3: Intermediate variant dump (variant suffix in filename)
YYYY-MM-DD-<type>-advocate.md or YYYY-MM-DD-<type>-critic.mdvariant_synthesis: false (this IS a variant, not a synthesis)emitted_by names the agent and variant (e.g., mlb-lineup-optimizer/advocate)variant_synthesis: truePattern 4: Low-confidence graceful degrade
confidence <= 0.3 and a red_team_findings entry flagging the missing data sourceNever 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.
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.
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.
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.
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.
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.
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.
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.
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:
signals/YYYY-MM-DD-<type>.mdsignals/YYYY-MM-DD-<type>-<id>.mdsignals/YYYY-MM-DD-<type>-<variant>.mdSignal ranges (see resources/methodology.md for the full table):
On validation failure:
{kind: signal_validation_failure, signal_type, reason, field, expected, actual, emitter, timestamp}.mlb-decision-logger with the failure entry.Key resources:
Inputs required:
overwrite flag (default false)Outputs produced:
tracker/decisions-log.md via mlb-decision-loggertesting
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.