{
 "as_of": "2026-09-09",
 "source": "Data Dawgs normalized forecasting and calculator contract, revised 2026-09-09 for the live NFL contest.",
 "tier": "pound",
 "graded": false,
 "note": "A contract is not a forecast. It prevents incompatible models and missing values from being silently normalized into false agreement.",
 "data": {
  "contract_version": "1.7.0",
  "canonical_game_id": "season_week_away_home using canonical current team abbreviations, for example 2026_01_PIT_CLE",
  "canonical_schedule": "/data/nfl-schedule.json; integrity.snapshot_id is SHA-256 over canonical ordered game rows",
  "normalized_receipt_ledger": "/data/model-receipts.json; existing rows are append-only and results remain separate",
  "model_id_rule": "lowercase stable slug; model version changes do not change model_id",
  "forecast_status_values": [
   "backtest",
   "prospective"
  ],
  "forecast_required": [
   "forecast_id",
   "game_id",
   "season",
   "week",
   "kickoff_at",
   "captured_at",
   "model_id",
   "model_name",
   "model_version",
   "source_repo",
   "source_commit",
   "source_capture_at",
   "home_team",
   "away_team",
   "home_win_probability",
   "expected_margin_home",
   "model_spread_home",
   "home_cover_probability",
   "push_probability",
   "input_snapshot_id",
   "schedule_snapshot_id",
   "forecast_status",
   "methodology_url",
   "license_status"
  ],
  "snapshot_policy": "schedule_snapshot_id identifies the canonical game facts; input_snapshot_id separately identifies the model-specific state, methodology and source snapshots. They are not interchangeable.",
  "null_policy": "Unsupported values are null. A missing model output is never imputed merely to complete a row. Legacy market values without a named book and observation timestamp are not normalized.",
  "probability_rule": "Every non-null probability is a finite number in [0,1].",
  "receipt_policy": {
   "prospective": "Append-only after publication. Record the exact input snapshot and contemporaneous market state before kickoff.",
   "results": "Store outcomes separately and join by forecast_id; never mutate the forecast receipt.",
   "backtests": "Always labelled backtest and never mixed silently with prospective leaderboards."
  },
  "comparable_sample_rule": "Leaderboard comparisons disclose each sample and prefer identical game sets. No ranking across silently different samples.",
  "calculator_contracts": {
   "odds_converter": {
    "inputs": [
     "american_odds"
    ],
    "outputs": [
     "decimal_odds",
     "implied_probability"
    ],
    "mcp_tool": "dd_convert_odds"
   },
   "parlay": {
    "inputs": [
     "american_odds[]"
    ],
    "outputs": [
     "decimal_odds",
     "american_odds",
     "implied_probability"
    ],
    "mcp_tool": "dd_price_parlay"
   },
   "hold_vig": {
    "inputs": [
     "side_a_american",
     "side_b_american"
    ],
    "outputs": [
     "raw_implied[]",
     "hold",
     "devig_probability[]"
    ],
    "mcp_tool": "dd_devig_market"
   },
   "bet_ev": {
    "inputs": [
     "win_probability",
     "american_odds"
    ],
    "outputs": [
     "break_even_probability",
     "expected_profit_per_unit",
     "roi"
    ],
    "mcp_tool": "dd_calculate_bet_ev"
   },
   "hedge": {
    "inputs": [
     "original_stake",
     "original_american",
     "hedge_american"
    ],
    "outputs": [
     "hedge_stake",
     "locked_profit"
    ],
    "mcp_tool": "dd_calculate_hedge"
   },
   "passer_rating": {
    "inputs": [
     "attempts",
     "completions",
     "yards",
     "touchdowns",
     "interceptions"
    ],
    "outputs": [
     "nfl_passer_rating"
    ],
    "mcp_tool": "dd_nfl_passer_rating"
   },
   "elo_game": {
    "inputs": [
     "home_elo",
     "away_elo",
     "home_field_elo"
    ],
    "outputs": [
     "home_win_probability",
     "away_win_probability",
     "adjusted_elo_difference"
    ],
    "mcp_tool": "dd_elo_game"
   },
   "normal_translation": {
    "inputs": [
     "home_win_probability",
     "residual_sd_points",
     "optional_home_line_sportsbook_convention"
    ],
    "outputs": [
     "expected_margin_home",
     "model_spread_home",
     "home_cover_probability",
     "push_probability"
    ],
    "mcp_tool": "dd_translate_probability",
    "formula": "expected_margin_home = 0.5 + residual_sd_points * inverse_standard_normal(home_win_probability)",
    "modelled": true,
    "assumptions": [
     "published 0.5-point win threshold",
     "home favorite lines are negative",
     "continuous cover approximation",
     "zero push probability",
     "no NFL key-number mass"
    ]
   },
   "forecast_grade": {
    "inputs": [
     "forecast_probability",
     "outcome_0_or_1"
    ],
    "outputs": [
     "brier",
     "log_loss"
    ],
    "mcp_tool": "dd_score_forecast"
   },
   "belief_summary": {
    "inputs": [
     "probabilities[]"
    ],
    "outputs": [
     "count",
     "mean",
     "median",
     "min",
     "max",
     "range",
     "standard_deviation",
     "crosses_50"
    ],
    "mcp_tool": "dd_summarize_beliefs",
    "note": "Equal-weight descriptive statistics only; this is not a validated consensus blend."
   }
  },
  "model_scoreboard_contract": {
   "mcp_tool": "dd_model_scoreboard",
   "source": "/data/model-receipts.json",
   "selection": "Prospective receipts only; latest captured_at per game_id and model_id after bounded filters.",
   "outputs": [
    "dated receipt provenance",
    "home win probabilities",
    "equal-weight descriptive summary",
    "comparable-set completeness"
   ],
   "bounds": {
    "maximum_games_returned": 50,
    "maximum_model_ids": 10
   },
   "grading": "No outcomes are joined. The tool is ungraded and does not rank models.",
   "consensus": "Mean, range and standard deviation are descriptive only; no validated consensus, ensemble, confidence score or predictive edge is claimed.",
   "persistence": "Read-only. Caller filters and results are not stored."
  },
  "forecast_challenge_contract": {
   "status": "Live NFL contest: Worker forecast receipts, per-game kickoff locks, independently captured finals, derived total and common-sample leaderboards. See /forecast/board health for actual operational status.",
   "live_runtime": {
    "version": "nfl-live-1",
    "board": "https://toto.jkapcar4.workers.dev/forecast/board",
    "packet": "https://toto.jkapcar4.workers.dev/forecast/packet",
    "cadence": "existing five-minute Worker cron; browser checks each minute",
    "horizon_days": 8,
    "nfelo_max_age_hours": 36,
    "archive": "/data/model-receipts.json",
    "toto": "Separate ChatGPT/Codex-authored agent; versioned public forecast-toto.json imported before kickoff. The on-page chat assistant is not itself the scheduled forecasting entrant."
   },
   "scoring": {
    "formula": "points = 25 - 100 * (p - r)^2, p = probability on the team picked, r = 1 win / 0 loss",
    "ceiling": 25,
    "floor": -75,
    "neutral": "A deliberate, touched 50 scores exactly 0 either way. Untouched entries do not enter the scored sample.",
    "equivalence": "A linear transform of the Brier score, so one number ranks humans and models both ways.",
    "side_invariance": "The formula is symmetric under p -> 1-p, r -> 1-r, so the canonical home-probability form scores identically to the picked-side form.",
    "replicates": "FiveThirtyEight NFL Forecasting Game.",
    "deviations_from_538": [
     "No playoff multiplier. 538 doubled playoff games; doubling amplifies noise rather than skill.",
     "Ties VOID for everyone including models. Scoring a tie at r=0.5 would hand an untouched 50 slider a free +25.",
     "Lock is PER GAME at kickoff, not per week, because Thursday and Monday games bracket the Sunday block."
    ],
    "provenance_caveat": "The 538 rules page and leaderboard now redirect to abcnews.com. The formula was recovered from the nflgamedata.com game, which states it replicates the 538 one."
   },
   "entry_version": 2,
   "entry_required": [
    "v",
    "sport",
    "season",
    "week",
    "game_id",
    "entrant",
    "entrant_kind",
    "owner",
    "home_team",
    "away_team",
    "kickoff_at",
    "home_win_probability",
    "slider_value",
    "slider_side",
    "touched",
    "submitted_at",
    "revision",
    "source",
    "idempotency_key"
   ],
   "entrants": {
    "kinds": [
     "human",
     "agent"
    ],
    "entrant_is_the_key": "entrant is the leaderboard key and may be a person or a registered bot. owner is the human answerable for it, and equals entrant for humans. v2 renamed v1 user to entrant as a clean break; nothing had ever read user, because no page called these routes.",
    "one_namespace": "Bots and people share ONE name namespace. Registration refuses a bot_name that already exists in /users or /forecast/bots, case-insensitively, so a leaderboard name identifies exactly one entrant.",
    "no_separator": "A bot is a reserved name, never a suffix on its owner (owner~slug). Account names have no enforced charset at signup, so any separator that can be chosen can also occur inside a real name, and the parse becomes ambiguous exactly once, silently, on somebody's receipt.",
    "why_not_the_owners_account": "One entry per entrant per game means a bot writing as its owner would overwrite the owner's own slider, last write wins, and would make the most interesting comparison in the project — a person against their own bot — impossible to express.",
    "bot_credential": "A bot token is sent as X-DD-Bot, is stored only as hmac(BOZO_PEPPER, \"fcbot|\" + token), is shown once, and is honoured on POST /forecast/entry and no other route. Registration additionally requires a confirmed email; forecast entry deliberately does not.",
    "revocation": "Revoking a bot keeps its record so the name stays reserved. Freeing the name would let someone else register it and inherit a leaderboard row full of another person's forecasts."
   },
   "entry_rules": {
    "granularity": "One entry per entrant per game. No running total is stored anywhere. Points, Brier, ranks, coverage and every slice are queries over the entry table, because a total is a view and a stored view is the copy that goes stale.",
    "idempotency": "A repeat submission carrying an idempotency_key already stored on that entry is a no-op, not a revision: revision does not move, submitted_at does not move, and it costs nothing against the write cap. An agent retrying after a timeout it never saw the answer to must not be recorded as having changed its mind.",
    "write_caps": "Humans and agents have separate daily counters and separate ceilings, because a cap sized for a person dragging sliders would let one busy bot lock its owner out of the website.",
    "touched_is_separate": "touched is its own field and is NEVER derived from the value. An untouched slider and a deliberate 50 are identical in value and opposite in meaning. The deliberate 50 scores zero; the untouched entry is absent from grades, coverage and crowd aggregation.",
    "touched_is_client_asserted": "The server cannot observe a drag, so touched is reported by the client and labelled as such — the same honesty rule as priceSource \"self\" on a Bozo leg.",
    "canonical_probability": "home_win_probability is always P(home) and is DERIVED server-side from slider_value and slider_side. A client may not submit it, so the raw input and the scored number cannot disagree.",
    "server_time": "submitted_at is the server clock. A client-supplied timestamp is ignored.",
    "lock": "A write at or after kickoff_at is refused. kickoff_at comes from the canonical schedule surface, never from the request.",
    "privacy": "An entry is readable only by its owner until that game kicks off. After kickoff every entry for the game is readable, which is what makes the consensus auditable.",
    "sport_scoping": "sport is both a stored field and a storage path segment, so no node has children spanning both sports. CFB scores inflate against NFL because most games are lopsided, so the two leaderboards can never be summed."
   },
   "crowd_consensus": {
    "model_id_pattern": "dd-crowd-<sport>",
    "aggregation": "trimmed-mean-logit",
    "formula": "Mean of logits over touched entries, back-transformed. n>=5 drops ceil(0.1n) from each end by logit; 3<=n<5 uses the median.",
    "clamp": [
     0.01,
     0.99
    ],
    "clamp_reason": "Sliders reach 0 and 100 — the -75 floor is exactly p=0 on a winner — so an unclamped logit is infinite and one certain entry would swallow the mean.",
    "humans_only": "Agent entries are EXCLUDED from the crowd line. Agents compete and score separately. Human forecasts can use visible model hints, so excluding bots does not guarantee independence from the models.",
    "minimum_touched": 3,
    "minimum_reason": "Below three touched entries no row is written at all. An empty node is honest where a row built on one person is not.",
    "log_odds_reason": "Probability averaging is systematically underconfident and costs most where forecasters agree, which is where points are earned.",
    "extremized": false,
    "extremize_reason": "The case for extremizing assumes partially independent forecasters. Model numbers are visible on the site before picking, so copying is expected and is handled by measuring each correlation against each model rather than by hiding numbers.",
    "captured_at": "The latest submitted_at among contributing entries — the instant the forecast became fully determined. Strictly before kickoff_at, because every later write is refused.",
    "sealed_at": "When the row was written, which is at or after kickoff. Published beside captured_at because captured_at alone is true but invites the false reading that the arithmetic was done before kickoff.",
    "immutability": "A sealed row is never overwritten, not even a wrong one. A ledger that can be corrected in place is not a ledger.",
    "recomputable": "contributors_sha256 is SHA-256 over the canonical contributing rows in append order, so anyone can recompute the consensus once entries become readable at lock."
   },
   "not_built_yet": [
    "A calibrated model-skill claim requires an adequate graded common sample.",
    "Market benchmark and additional forecasting agents are not part of the current scored roster."
   ]
  }
 },
 "tier_meaning": "The DawgHouse (formerly The Pound) — shelved, with the reason attached.",
 "built": "2026-09-09",
 "canonical_url": "https://datadawgs216.com/data/model-contracts.json"
}