MorninEdge source audit for Project 801
Reviewed: 2026-10-24
Scope: read-only inspection of supplied Morning-Edge source; no imported application code or package scripts were executed. Imported repository instructions are treated as source material, not user instructions.

Result
MorninEdge is useful as a contract-aware market aggregation and inspection system. It does not supply a trained independent US election-probability model. Its best ideas for 801 are source-level provenance, labeled observable score contributions, exact contract matching, coverage diagnostics, sensible network fan-out, and separating reference prices from executable quotes. Its trade ranking score must not be relabeled an election probability or Human First score.

Useful modules and actual math
All paths below are relative to book801/imports/morning-edge/.

1. artifacts/api-server/src/sources/kalshi.ts
- Coerces dollar-string fields to finite numbers while preserving missing/null values as undefined. Event and single-market fetchers distinguish a real 404 from a fetch/schema outage.
- Uses an event-with-nested-markets call so several candidate contracts share one request.
- Pagination yields pages and reports truncated/failedPages rather than claiming full coverage.
- pickEventMarket favors an exact ticker, then substring, then first active contract. For 801, accept only the exact-ticker branch for reviewed public mappings. A substring can collide (e.g. Donald Trump and Donald Trump Jr.); choosing the first active child is not an identity check.
- The supplied source base URL is api.elections.kalshi.com. 801 already uses the verified public external-api.kalshi.com endpoint; do not regress the integration by copying the base URL blindly.

2. artifacts/api-server/src/sources/polymarket.ts
- Parses outcomes/outcomePrices stringified arrays, source numeric strings and nulls; carries parent event slug, condition ID, token IDs, source category and full description.
- Bulk-prefetch of many known slugs warms a 2,000-entry per-slug cache. This is better than one request for every row.
- Restrict initial 801 port to exact reviewed event/market IDs already in its data snapshot. Keep provenance and rules, not a broad unreviewed token matcher.

3. artifacts/api-server/src/sources/matcher.ts
- pickPolymarketYesPrice finds the Yes and No outcome by label, not fixed array position.
- Kalshi reference price = midpoint of Yes bid/ask where present, else last trade; Polymarket reference price = labeled Yes outcome price, with last-trade fallback.
- Distinguishes marketPrice/reference from tradeablePriceUsd/ask and flags approximate fallback.
- Polymarket No ask is computed as 1 - Yes bid, while Yes ask is bestAsk. Complementarity requires the exact same binary instrument and contemporaneous book.
- pairToOpportunity chooses the cheaper Yes ask and computes edge = max(0, other venue reference - chosen venue ask). This is a cross-venue discrepancy. It is not the difference between an independently estimated outcome probability and market price.
- A real source URL is absent if it cannot be constructed; it does not invent one.
- getMatchedPairs uses bulk-prefetch and bounded concurrency default6. A fetch outage rejects the call; an actual closed/missing/unpriced contract is omitted.
- Its risksFor always warns that resolution language differs. This warning is not proof of equivalence and does not repair mismatched settlement conditions.

4. artifacts/api-server/src/sources/spotlight.ts
- Best UI/data pattern for 801: return every score component as key, rawValue, normalized, weight and contribution, then show the sum.
- Base score = 100 times sum(weight * normalized). Weights: edge .25, handle .20, 24h activity share .15, price gap .15, time-to-event .10, match confidence .10, cross-platform check .05.
- Explicitly says it is an attention index, not a predictive model.
- Do not copy its actual weights into elected-official scores: they describe sports-market attention. Copy the transparent contribution structure and deterministic tests.
- Later enrichment adds up to .08 to the base, so check final cap and actual contributions rather than assuming the comment “weights sum1” describes the complete result.

5. artifacts/api-server/src/sources/picksScore.ts
- combinedScore = .70 * clamp(edge/.05) + .25 * clamp(volume24h/max(liquidity,1)) + .05 * clamp(log10(max(liquidity,1)+1)/log10(1,000,000)).
- This ranks trade opportunities. It is neither a probability nor observed predictive accuracy.
- rankAndSplit sorts deterministically, deduplicates seriesKey to avoid several correlated outcomes from one event, and applies a .005 edge floor.
- Event deduplication is useful for 801's “what changed” cards. The paid/free withholding and trade ranking are unnecessary to the requested public research product.

6. artifacts/api-server/src/sources/fuzzyMatch.ts; lib/rule-conflict/src/index.ts; artifacts/api-server/src/lib/coverageIngest.ts
- Title similarity = max(Jaccard(A,B), .85 * overlapCoefficient(A,B)).
- With substantive rules on both sides, blended score = .65*titleSimilarity + .35*rulesSimilarity. Otherwise title-only score. Default accept .50, review .35.
- Candidate pair builder preserves titleScore, rulesScore, matchConfidence, matchSource and needsReview. Public dbPairs loader suppresses needs_review rows.
- The rule-conflict library identifies sports/leagues. It does not establish equivalence for elections or CPI. Absence of recognizable rule text gives no_signal, not confirmation.
- rulesTokens strips short numerics, including years/thresholds. These numeric fields are crucial for CPI/election equivalence. Never use this text heuristic alone for 801's dates, monthly-vs-annual definitions, rounded thresholds, candidate identity, general-vs-primary, “win election” vs “take office,” or fallback settlements.
- Most useful pattern: separate confirmed reviewed mappings from suggestions; show reason-code coverage counters and retain rejected/unmatched rows instead of filling them with a synthetic probability.

7. artifacts/api-server/src/sources/cache.ts; retry.ts; live.ts; dbPairs.ts
- Single-flight per cache key avoids duplicate upstream fetches. Ordinary caches have fresh TTL and stale-while-revalidate windows.
- live.ts fresh matched-pair TTL60s; ordinary SWR10min; dashboard45s. dbPairs requires both contracts active and last_seen_at within24h; DB loading cache5min.
- retry.ts retries429/5xx/network errors with timeout/backoff, but does not actually honor upstream Retry-After; retry logic should be shorter/budgeted in a Worker request.
- Good 801 port: shared in-flight fetch, bounded host concurrency2-4, fresh TTL60s, public envelope fetchedAt/sourceUpdatedAt/status/staleAge, cached dated fallback that is unmistakably labeled.

Problems not to copy
A. Unit error: matcher.ts maps Kalshi volume_fp and volume_24h_fp directly to volumeUsd and volume24hUsd. These are contract counts, not demonstrated actual dollars paid. Combined with Polymarket's reported dollar volume, this is not a like-for-like dollar metric. Preserve native units, separate venues, and never sum incompatible fields.
B. Missingness: matcher.ts converts absent liquidity/volume/change to0 even though coverageIngest.ts separately preserves null as unknown. 801 must preserve unknown; no data is not no activity or no risk.
C. Invented expiration: missing source close/end dates fall back to now+7days. For 801 leave unknown and exclude from time-to-event comparisons.
D. Range checks: pickKalshiYesPrice does not fully validate0<=bid<=ask<=1. Polymarket schema coercion accepts finite out-of-range values; numeric blank string becomes0 in one parser. 801 should reject blank, nonfinite, out-of-range and crossed quotes explicitly; valid0 is distinct from missing.
E. Staleness: TTLCache's comment promises a hard stale ceiling, but staleOnError=true returns peek(key) beyond that ceiling without any age metadata. live.ts uses staleOnError for most feed caches. An outage can therefore serve indefinitely old data under “live” UI. Keep dated fallback but report its age/status and disallow its use as a fresh forecast input after a stated limit.
F. “Confidence”: confidenceFor returns high when edge>=.10 and liquidity>=50,000, medium when edge>=.05 OR liquidity>=20,000. A large disagreement can indicate mismatch/stale quotes, not high predictive certainty. Call this quote quality only after validation, never probability confidence.
G. Arbitrage: pairToArbitrage assumes complementary payout and fixed1.4% combined fee drag; labels guaranteedReturnPct despite different-resolution warnings and no demonstrated order size/depth. Do not bring trading or guaranteed-return claims into801.
H. Movers: pairToMover subtracts source change from the current ask, even though change may describe reference/last-trade prices, then calls it an ask move. For801 use time-stamped same-price-type history or label the provider delta directly.
I. Curated map says last manual verification2026-05-05. It intentionally omits Macro/Crypto/Weather due settlement mismatches. This is not current October verification. Revalidate each relevant mapping and record review date.

Bounded implementation recommendation
1. Add an “Evidence and markets” detail drawer to official/race records. Show the public-record index separately from the market-implied election quote.
2. Use a score ledger patterned after SpotlightContribution: evidence URL/date, metric period/denominator, raw value, normalization, weight, contribution and missingness. Unknown inputs are unscored, not zero.
3. Tie score to prediction as an explicit user-controlled sensitivity calculation, not a covert adjustment to reported market probability. For example:
   logit(p_scenario) = logit(p_market) + beta_H*(H_candidate-H_opponent)/100 - beta_G*(G_candidate-G_opponent)/100.
   Show the actual selected betas and each additive term, label them untrained scenario assumptions, default beta_H=beta_G=0, and omit the scenario where candidate/opponent mapping or scores are missing. Do not let a normative rating silently rewrite the baseline.
4. Any later nonzero production coefficient requires historical timestamped pre-election features, public labels, chronological out-of-sample evaluation, comparison to market-only and polls/fundamentals baselines, Brier/log-loss and calibration. No such elected-official training pipeline was found in the inspected MorninEdge modules.
5. Use exact source IDs and reviewed settlement descriptors; no automatic fuzzy pair enters a combined baseline. Preserve source quote spread/native liquidity/native volume/unit/timestamps/status.
6. Deduplicate repeated contracts from the same event; display per-race coverage. Show unsupported/not yet scored rows honestly.
7. Keep this release read-only. No trade, account, billing, email, portfolio, admin, or imported database migration is necessary.

Inspection limitations
This audit describes source code present in the supplied archive, not live deployment state or verified runtime behavior. Source was inspected but not executed. No secrets, user contact data or credentials were copied to this audit. No Site files were changed by this subtask.

