# Freedom Fund dashboard

The public dashboard lives at https://www.masonearl.com/ff. Its default scanner terminal collects real Solana observations and runs prospective paper experiments. The historical arena compares five fixed ETF strategies, and a separate append-only ledger holds sourced live and paper agent observations. None of these endpoints executes or approves real trades.

## Scheduled Solana scanner

`GET /api/freedom-scanner` returns the same observations rendered in the terminal: token checks, source dates and links, paper books, ranks, decision tape, reported holder owners, and replay frames. `GET /api/freedom-scanner?view=contract` describes the collector. Reads never trigger a collection. The browser refreshes visible latest-view data once per minute; it does not interrupt a replay.

The production Vercel cron requests `/api/freedom-scanner?run=1` at minutes 7, 22, 37, and 52 of each UTC hour. Vercel supplies `Authorization: Bearer <CRON_SECRET>`; unauthenticated calls return 401. Agents may trigger the same collection with `POST /api/freedom-scanner` using the existing `FF_AGENT_WRITE_TOKEN`. Keep both credentials server-side. No request accepts strategy overrides, destination URLs, wallet secrets, or orders.

The collector uses an expiring distributed lock and checks lock ownership again before saving the entire state atomically. Concurrent requests return `busy`; observations less than ten minutes apart return `current` without advancing any paper book. Unavailable discovery or quote services preserve the previous state. Missing individual risk responses remain explicit holds. The read API labels observations older than 35 minutes `delayed`; it never advances timestamps just because a browser refreshed.

Source adapters:

- [DEX Screener](https://docs.dexscreener.com/api/reference): up to 20 valid Solana addresses from the latest token-profile feed, plus queued/held tokens. This is a selective profile-update sample, not comprehensive mint discovery. Quotes and liquidity are indicative provider observations. The most liquid returned pool is chosen for a new token; queued and held positions remain pinned to their original pool.
- [Solana RPC](https://solana.com/docs/rpc/http/getmultipleaccounts): confirmed parsed mint state for authorities and token extensions. The default is the public mainnet endpoint; an operator can set server-side `FF_SOLANA_RPC_URL` for an authenticated provider. Nothing submits or signs a transaction.
- [Rugcheck](https://api.rugcheck.xyz/swagger/index.html): risk flags, top holder owners, known pools, and pool-lock reports. Free reports may be cached. `detectedAt` is displayed as the provider's detection timestamp, not claimed as a verified update time. The conservative gate holds reports older than one hour. Report retrieval does not prove current contract safety.

All 11 gates must pass before a token becomes a paper candidate: valid USD quote, at least $25k pool liquidity, pair at least five minutes old, revoked mint and freeze authorities, no unmodeled token extensions, recent risk-report detection, no provider danger flag or reported rug, largest reported non-pool owner at most 10%, up to ten reported owners at most 50% combined, and at least 90% reported LP lock for the selected pool. These are research filters, not proof that a token is safe. Grouped holder data is limited by the provider's top-holder sample; related wallets and changing lock terms can be missed. Known pool accounts are explicitly excluded, not assumed to be profitable traders. Missing data never passes. Rejection counts are failed checks, not prevented rugs.

Four fixed books begin with $100 each and no external flows:

- `liquidity-v1`: choose the candidate with greatest pool liquidity, requiring at least $100k.
- `flow-v1`: choose highest hourly buys/sells ratio, requiring at least 100 transactions and ratio at least 1.3 (zero sells uses a denominator of one).
- `momentum-v1`: choose the greatest positive hourly price move up to 50%.
- `cash-v1`: cash control with no assumed yield.

A discovered signal queues for a later observation and expires after 30 minutes. Current risk evidence must still pass before a fill; entry uses the later observed quote, not the discovery price. Each active strategy takes at most one position using 20% of available equity and models a 1% debit for combined fees/slippage on each side. A position exits at the next observed liquid quote after a −10% price move, +25% price move, six-hour holding limit, or failed risk gate. Stops can gap; they are not guaranteed fills. No gas, execution-depth model, or personal taxes are included. New entries stop below $80 equity. An exited token is excluded from immediate reselection until another token is exited.

If a held token loses its price or minimum liquidity coverage, its last mark is retained with its original timestamp, no exit is fabricated, and that book's rank is suspended. The cash/control books do not inherit its stale status. Maximum drawdown is observed at scan times and can miss intervening losses. Ranks require at least two observations, use net equity, and preserve ties. Costs, cash, open quantities, realized P&L, and pending signals are exposed. `paper-entry`/`paper-exit` events are simulations, never claims of executed trades.

State is isolated under `freedom-fund:scanner-1.0:` in the existing KV store. Replay retains 96 scans; book curves retain 1,000 observations; the decision feed retains 300 entries. Lifetime counters count evaluations including repeated tokens. Start dates, version, and cumulative economics persist. Changing strategy economics requires a new experiment version or an explicit migration, not silently rewriting the track record. To pause collection, remove the scanner's cron entry and redeploy; preserve state for audit. The implementation is deterministic, versioned code, not a self-rewriting agent.

The wallet research queue contains actual reported public holder owners, ordered by tokens observed and largest supply share. No wallet P&L, intent, insider identity, or trading skill is inferred from a balance. Wallet copying remains unavailable until complete transaction/flow evidence and prospective performance exist. The published Robinhood snapshot and Solana scanner are separate data sources; Robinhood is not connected by this collector.

## What is connected

- Daily historical prices: Yahoo Finance chart data for SPY, QQQ, IWM, TLT, GLD. Adjusted closing prices include the provider's split and distribution adjustments. Only completed sessions are included. This is an unofficial public data endpoint without an availability guarantee, not a paid real-time quote feed.
- ETF price synchronization: refresh on dashboard/API requests, at most once per 15 minutes per shared cache cycle. The historical view requests updates every five minutes while visible. This is separate from the scheduled Solana paper collector.
- Live account: the published September 11, 2026 portfolio snapshot. This is not a brokerage connection. Holdings are never presumed unchanged by replacing their old prices with new quotes.
- Scout digest: the Sources view preserves the September 12 published trader queue, research bench, process notes, and third-party FOMO Radar claims. This registry is a versioned published snapshot, not a live sync to Robinhood Social or FOMO Radar. Priority and outside claims never determine a performance rank. `data/freedom-fund/scout-digest.json` is the canonical registry; its strategy IDs can be used in future sourced portfolio records.
- Agent observations: authenticated public records in a separate `freedom-fund:v1:` namespace in the site's existing KV store. Read failures are explicitly shown; seed records are never presented as a successful ledger refresh.
- Fallback: bundled market history and generated snapshots for each period. Failed refreshes preserve original source dates and display a saved-data notice.

## Reading the shared data

No authentication is needed for public reads:

```sh
curl 'https://www.masonearl.com/api/freedom-fund?period=126'
curl 'https://www.masonearl.com/api/freedom-fund?view=ledger'
curl 'https://www.masonearl.com/api/freedom-fund?view=contract'
```

Periods are 21, 63, 126, and 252 trading sessions. The response includes full chart observations, strategy rules, holdings, simulated rebalances, net returns, drawdowns, costs, source timestamps, engine version, recorded portfolios, decisions, and sync status. `live`, `paper`, and historical `strategies` are separate arrays. A missing return or rank is `null`, never an invented zero. The JSON download in the dashboard exports the same response.

## Writing a public record

Use `POST /api/freedom-fund`, `Content-Type: application/json`, and `Authorization: Bearer <FF_AGENT_WRITE_TOKEN>`. Keep the token in the agent/server environment, never in a prompt, browser storage, webpage, or repository. The server uses `FF_KV_REST_API_URL` / `FF_KV_REST_API_TOKEN`, falling back to the site's `TASKS_KV_KV_REST_API_*` or `KV_REST_API_*` variables.

The CLI validates the record before sending it:

```sh
node --env-file=/path/to/agent.env scripts/ff-record.js /path/to/public-record.json
```

Records must explicitly declare `visibility: "public"`. Do not submit account numbers, credentials, private notes, or personal identifiers. Unknown fields are rejected. Source links must use HTTPS; they are evidence links and are not fetched by this endpoint.

A snapshot requires:

- `id`: stable unique lowercase ID; reuse it when retrying.
- `type`: `snapshot`.
- `visibility`: `public`.
- `mode`: `live` or `paper`.
- `strategyId` and `strategyName`: stable identity. Use a new versioned ID when the strategy rules change.
- `asOf`: timestamp with timezone, using the actual valuation time rather than the upload time.
- `source`: `{ "name": "public evidence description", "url": "https://..." }`.
- `currency`: `USD`.
- `equity`: total portfolio value, including cash and actual incurred fees.
- `flowSincePrevious`: external deposits minus withdrawals at the end of the observation interval. Use zero when there was no external flow. Fees and trading proceeds are not external flows.
- Optional `cash` and `positions`: long positions `{symbol, quantity, cost, mark}`. When positions are supplied, cash is required and their marked values plus cash must reconcile to equity within $0.02.

A decision uses the same identity, source, timestamp, visibility, and mode fields, with `type: "decision"`, `action` (`hold`, `research`, `propose`, `reject`, or `outcome`), and `summary`. It can include `thesis`, `counterEvidence`, and `nextCheck`. An action is a journal entry, not trading authorization.

Successful new records return HTTP 201. An identical retry returns 200 with `duplicate: true`. A conflicting ID or a second snapshot at the same strategy/mode/timestamp returns 409. Inserts are atomic and append-only. Invalid payloads return 400, unauthorized writes 401, and storage outages 503. On uncertain outcomes, retry the same ID and payload. The current ledger has a 10,000-record guard; add archival/pagination before expanding beyond that.

## Historical simulation method

Engine version: `2026-09-12.1`. All five strategies use the intersection of available trading dates across the same fixed ETF universe and identical selected start/end dates. A minimum of 100 trailing sessions is available before the first simulated decision.

Each begins with $100 cash at the baseline close. Signals through the previous close execute at the next close. Existing holdings receive today's adjusted-close return before that day's rebalance. The initial purchase also pays transaction costs. Cash earns zero; there is no leverage, shorting, or final liquidation. A 5-basis-point one-way cost applies to each dollar of traded notional; rotation from one fully invested asset to another has two legs. Target weights are set after the proportional cost debit, with weight drift between rebalances.

- **S&P 500 buy & hold:** enter SPY once, then hold. This benchmark pays the same entry cost.
- **Five-asset balance:** equal weight in all five ETFs, rebalanced every 21 sessions from the start of the selected window.
- **100-day trend:** SPY when its previous close is above the trailing 100-session average; cash otherwise.
- **Relative momentum:** every 21 sessions choose the strongest positive 63-session ETF return; otherwise cash. Ties follow the fixed symbol order.
- **20-day mean reversion:** enter SPY after a previous-close z-score below −1.5 against the trailing 20 sessions; exit at z-score ≥ 0. Population standard deviation; a zero standard deviation gives a neutral z-score.

Rank is net cumulative return, not a claim of statistical significance. Excess return is the percentage-point difference from the SPY benchmark. Maximum drawdown includes the entry cost and measures the greatest observed peak-to-trough loss. Reallocations are simulated portfolio changes, not completed trades or a win-rate denominator. The API also includes annualized daily-return volatility (population standard deviation × √252, at least 20 intervals) and a zero-risk-free-rate Sharpe estimate (daily mean / population standard deviation × √252, at least 60 intervals); neither determines rank. Each selected window is a fresh simulation; switching windows can change signals and rebalance dates.

These are exploratory historical tests, not out-of-sample evidence. The fixed universe is selected today and introduces selection bias. Adjusted history can be revised; it is not a point-in-time archive. Prices approximate reinvested distributions and are not executable historical fills. Costs do not include taxes, market impact, research/API spending, or the exact economics of fractional-share execution. Never silently count these tests as forward paper or live performance.

## Recorded portfolio method

The first snapshot establishes a baseline. For each subsequent observation, the return factor is `(equity - flowSincePrevious) / previousEquity`. Compounding those factors gives a cash-flow-adjusted return. This assumes external flows occurred at the end of the interval; use valuations immediately before/after material flows when that convention is unsuitable.

Comparative ranks require at least two exact shared valuation timestamps across eligible strategies in the selected calendar window. No marks are interpolated. Timestamps between those endpoints are retained for each strategy. Sparse observations can miss intervening drawdowns. The published inconsistent seed record is quarantined from calculations; later reconciled observations can establish a new baseline without erasing the original evidence. Inconsistent latest valuations cannot rank.

## Development and operations

```sh
npm run ff:sync   # fetch real prices and regenerate all four saved views
npm run ff:test   # calculation, provenance, request validation, and API tests
npm run vercel:dev
```

`npm run dev` is static-only and cannot run the API. A saved-data fallback will be shown in that mode. The engine is in `server/ff-engine.js`; the provider and ledger adapter in `server/ff-data.js`; the contract in `server/ff-contract.js`; the API in `api/freedom-fund.js`. No brokerage keys or trade-execution path are present.
