finding · findings/evolution/shared_data/manifest.md
A manifest is just a master list — like the index card catalogue in a library that tells you what books exist, where each one sits on the shelf, and whether it's in good condition. This page documents manifest.json: the master list of every chunk of crypto market data the research used to pull together, what each entry means, and the rules that kept that list trustworthy.
fetch_multi_slice.py) no longer exist — the active probe (orthogonality_probe.py) now reads each data cell live from the database and writes its results elsewhere. The manifest was never actually populated. The schema below is kept for reference and possible future revival. Crypto-only since version 2.manifest.json is a JSON file — JSON is a simple, human-readable text format that computers read easily (think of it as a tidy outline of labels and values).Two separate quality checks — one that evaluates measurement metrics, one that evaluates candidate features — both needed to look things up programmatically (i.e., with code, not by hand). Specifically, they needed to discover:
effective_start filter).bigblack server, so a script can open it.At the very top, the manifest carries a few bookkeeping facts about the whole catalogue, then two big lists: cells (the data chunks) and fetch_runs (a log of each time the catalogue was built or refreshed).
{
"schema_version": 1, // bump when this schema changes
"pre_spec_version": 1, // which pre-spec.md version produced this
"pre_spec_file": "pre-spec.md",
"generated_at": "2026-05-23T14:32:00Z", // ISO timestamp of last fetch
"host": "bigblack", // host that ran the fetcher
"data_root_on_bigblack": "/home/nasimubd/shared_data/",
"cells": [ ... ], // per-cell records (see below)
"fetch_runs": [ ... ] // per-run log entries (see below)
}
A schema is just the agreed-upon shape/layout of the data — which fields exist and what type each is. schema_version is a number bumped whenever that layout changes, so old readers can tell they're looking at a newer format.
Each cell in the cells list looks like this — a complete catalogue card for one slice of data:
{
"cell_id": "crypto_BTCUSDT_100dbps_slice01",
"substrate": "crypto",
"symbol": "BTCUSDT",
"threshold_dbps": 100,
"slice_id": "slice01",
"slice_start_iso": "2026-01-01T00:00:00Z",
"slice_end_iso": "2026-02-28T23:59:59.999999Z",
"applicable": true,
"applicable_reason": "in range; effective_start satisfied",
"bar_count": 84321,
"non_null_frac_per_col": {
"ofi": 1.0,
"vwap": 1.0,
"kyle_lambda_proxy": 1.0,
"lookback_hurst": 0.7234,
...
},
"fetch_timestamp_ingestion": "2026-05-23T14:32:18Z",
"parquet_path": "/home/nasimubd/shared_data/crypto/BTCUSDT_100dbps_slice01.parquet",
"file_size_bytes": 4521734,
"sha256": "abc123def456..."
}
| Field | Type | What it means (plain words) |
|---|---|---|
cell_id | string | The unique name of this chunk, built by gluing the coordinates together: <substrate>_<symbol>_<threshold>dbps_<slice_id>. A slug like this is a short, machine-friendly label. No two cells share one. |
substrate | "crypto" or "forex" | Which market the data came from — i.e., which database table backed the fetch. (Today it's crypto-only.) |
symbol | string | The trading pair, e.g. "BTCUSDT" (Bitcoin vs. a dollar-pegged coin) or "EURUSD" (euro vs. US dollar). |
threshold_dbps | int | The sensitivity setting for forming a "bar," e.g. 100. (dbps = decimal basis points; 100 dbps = 0.1%. Smaller = more, finer bars.) |
slice_id | string | Which time window, "slice01" through "slice24" — the data is cut into fixed calendar chunks. |
slice_start_iso, slice_end_iso | string (ISO UTC) | The exact start and end of that calendar window, in a standard timestamp format. These mirror the locked plan in pre-spec.md. |
applicable | bool | True/false: was data actually fetched for this cell? (False when the slice doesn't make sense for this symbol.) |
applicable_reason | string | If not applicable, the reason — e.g. "symbol effective_start 2023-05-03 > slice_start 2020-04-01" (the coin didn't exist yet in that window). |
bar_count | int (or null) | How many rows of data the chunk holds. null when the cell isn't applicable. |
non_null_frac_per_col | dict | A per-column "how-full-is-it" score: the fraction of rows that actually have a value (1.0 = completely filled, 0.72 = about a quarter missing). A quick data-quality read per column. |
fetch_timestamp_ingestion | string (ISO UTC) | The moment the fetcher pulled this particular cell. |
parquet_path | string | The full file location on the bigblack server where the data file lives. |
file_size_bytes | int | How big the file is on disk, in bytes. |
sha256 | string (hex) | A SHA-256 fingerprint — a long code computed from the file's exact contents. If even one byte changes, the code changes, so it acts as a tamper-proof seal for reproducibility. |
Besides the data chunks, the manifest keeps a diary: one entry every time the fetcher ran, recording how it went.
{
"run_id": "20260523T143200Z",
"host": "bigblack",
"started_at": "2026-05-23T14:32:00Z",
"completed_at": "2026-05-23T14:50:18Z",
"pre_spec_version": 1,
"cells_attempted": 552,
"cells_fetched": 550,
"cells_skipped_already_fetched": 0,
"cells_skipped_not_applicable": 2,
"cells_failed": 0,
"cpu_env": {
"OPENBLAS_NUM_THREADS": "1",
"OMP_NUM_THREADS": "1",
"MKL_NUM_THREADS": "1",
"NUMEXPR_NUM_THREADS": "1"
},
"loadavg_at_start": [6.81, 6.90, 7.27],
"nproc": 32
}
cells_attempted), succeeded (cells_fetched), skipped (already there, or not applicable), and failed.cpu_env block pins each math library to a single thread — a precaution so parallel work stays predictable and doesn't fight over the machine.loadavg_at_start (how busy the machine was) and nproc (how many CPU cores it had, here 32).duration_sec, pre_spec_hash_sha256, click_house_reads_total_bytes — but were never implemented. They were filed as "CONCEDE-FOLLOW-UP" items from the PR #501 review (i.e., acknowledged gaps to fix later, before any real run).The point of a machine-readable catalogue is that a few lines of code can answer real questions instantly. Examples from the doc:
import json
from pathlib import Path
manifest = json.loads(Path("findings/evolution/shared_data/manifest.json").read_text())
btc_cells = [c for c in manifest["cells"] if c["symbol"] == "BTCUSDT"]
print(f"BTCUSDT cells: {len(btc_cells)}")
btc_100dbps = [c for c in manifest["cells"]
if c["substrate"] == "crypto"
and c["symbol"] == "BTCUSDT"
and c["threshold_dbps"] == 100
and c["applicable"]]
parquet_paths = [c["parquet_path"] for c in btc_100dbps]
# Audit-side spike reads each path; the 24 slices give it K=24 per-pair values
jqjq is a small command-line tool for slicing JSON from the terminal.
# Total cells
jq '.cells | length' findings/evolution/shared_data/manifest.json
# By substrate
jq '.cells | group_by(.substrate) | map({substrate: .[0].substrate, count: length})' \
findings/evolution/shared_data/manifest.json
# List non-applicable cells with reasons
jq '.cells[] | select(.applicable == false) | {cell_id, applicable_reason}' \
findings/evolution/shared_data/manifest.json
The manifest was designed with built-in guarantees — and the doc is honest about exactly how far each one goes:
| Property (the promise) | How it's enforced — and the caveat |
|---|---|
Every cell has a unique address (cell_id) | Built deterministically from the coordinates. Caveat: if a duplicate ID is written, the new one silently overwrites the old — there is no collision error yet. |
| Time windows come from one place | Start/end dates are copied from the fetcher's hard-coded SLICES list. Caveat: there's no automatic check that those match pre-spec.md, so drift between the two wouldn't be caught at write time. (Filed as a follow-up.) |
| The fingerprint matches the file | The sha256 is computed and stored at write time, so re-runs can detect a file changed in place. Caveat: it does not guarantee bit-for-bit identity across machines, because the compression can differ across software versions. |
| Not-applicable cells stay empty | When applicable: false, the path and row count are forced to null. No phantom files. |
| Re-running doesn't create duplicates | Writes are idempotent (safe to repeat) — keyed by cell_id, already-fetched cells with a valid fingerprint are skipped. |
These were accurate as of pre-spec v1. Stricter rules — a hard error on duplicate IDs, and a write-time cross-check of timestamps against pre-spec.md — were tracked as follow-up items to add before the first real run.
| Trigger | Effect |
|---|---|
| Run the fetcher for the first time | Every applicable cell gets fetched; the list grows to ~552 entries. |
| Re-run the fetcher later | Already-fetched cells are skipped; a cell is only refreshed if its file went missing or its fingerprint no longer matches. |
| Upgrade to pre-spec v2 | New cells are added; old cells are kept and tagged pre_spec_version: 1, new ones tagged 2. |
| Someone deletes a data file by hand | The next run notices the missing file and re-fetches it. |
Hand-editing manifest.json | Don't. The manifest is fetcher-owned. To change scope, edit pre-spec.md instead. |
pre-spec.md — what cells should exist (v2, crypto-only): the locked plan.orthogonality_probe.py — the active probe that replaced the fetcher (reads the database live; writes results/, not this manifest).README.md — the folder hub for the shared data layer.manifest.json was the trustworthy "table of contents" for the shared crypto data — a unique address, quality score, location, and tamper-proof seal for every slice — but it's now legacy: the project moved to reading data live, so this schema is kept on the shelf for reference, not in active use.