coordinator-node 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coordinator_node-0.1.0/.dev.env +28 -0
- coordinator_node-0.1.0/.dockerignore +2 -0
- coordinator_node-0.1.0/.gitignore +18 -0
- coordinator_node-0.1.0/.local.env +43 -0
- coordinator_node-0.1.0/.production.env +39 -0
- coordinator_node-0.1.0/.python-version +1 -0
- coordinator_node-0.1.0/Dockerfile +16 -0
- coordinator_node-0.1.0/Makefile +15 -0
- coordinator_node-0.1.0/PKG-INFO +120 -0
- coordinator_node-0.1.0/README.md +103 -0
- coordinator_node-0.1.0/SKILL.md +174 -0
- coordinator_node-0.1.0/base/Makefile +17 -0
- coordinator_node-0.1.0/base/README.md +14 -0
- coordinator_node-0.1.0/base/SKILL.md +38 -0
- coordinator_node-0.1.0/base/challenge/README.md +17 -0
- coordinator_node-0.1.0/base/challenge/SKILL.md +30 -0
- coordinator_node-0.1.0/base/challenge/pyproject.toml +14 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/__init__.py +3 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/examples/README.md +9 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/examples/__init__.py +9 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/examples/mean_reversion_tracker.py +58 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/examples/trend_following_tracker.py +57 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/examples/volatility_regime_tracker.py +84 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/schemas/README.md +5 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/scoring.py +10 -0
- coordinator_node-0.1.0/base/challenge/starter_challenge/tracker.py +11 -0
- coordinator_node-0.1.0/base/node/.local.env +48 -0
- coordinator_node-0.1.0/base/node/.local.env.example +30 -0
- coordinator_node-0.1.0/base/node/.production.env.example +39 -0
- coordinator_node-0.1.0/base/node/Dockerfile +26 -0
- coordinator_node-0.1.0/base/node/Makefile +51 -0
- coordinator_node-0.1.0/base/node/README.md +22 -0
- coordinator_node-0.1.0/base/node/RUNBOOK.md +45 -0
- coordinator_node-0.1.0/base/node/SKILL.md +53 -0
- coordinator_node-0.1.0/base/node/config/README.md +4 -0
- coordinator_node-0.1.0/base/node/config/callables.env +1 -0
- coordinator_node-0.1.0/base/node/config/scheduled_prediction_configs.json +11 -0
- coordinator_node-0.1.0/base/node/deployment/README.md +6 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/docker-entrypoint.sh +18 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/models.dev.yml +8 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/orchestrator.dev.yml +33 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/main.py +8 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/requirements.txt +1 -0
- coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/tracker.py +18 -0
- coordinator_node-0.1.0/base/node/deployment/report-ui/config/global-settings.json +15 -0
- coordinator_node-0.1.0/base/node/deployment/report-ui/config/leaderboard-columns.json +45 -0
- coordinator_node-0.1.0/base/node/deployment/report-ui/config/metrics-widgets.json +123 -0
- coordinator_node-0.1.0/base/node/docker-compose.yml +233 -0
- coordinator_node-0.1.0/base/node/extensions/README.md +10 -0
- coordinator_node-0.1.0/base/node/plugins/README.md +18 -0
- coordinator_node-0.1.0/base/node/pyproject.toml +11 -0
- coordinator_node-0.1.0/base/node/runtime_definitions/__init__.py +1 -0
- coordinator_node-0.1.0/base/node/runtime_definitions/contracts.py +222 -0
- coordinator_node-0.1.0/base/node/scripts/backfill.py +93 -0
- coordinator_node-0.1.0/base/node/scripts/capture_runtime_logs.py +73 -0
- coordinator_node-0.1.0/base/node/scripts/check_models.py +99 -0
- coordinator_node-0.1.0/base/node/scripts/verify_e2e.py +138 -0
- coordinator_node-0.1.0/clean-data.sh +7 -0
- coordinator_node-0.1.0/coordinator_node/__init__.py +0 -0
- coordinator_node-0.1.0/coordinator_node/config/__init__.py +1 -0
- coordinator_node-0.1.0/coordinator_node/config/extensions.py +18 -0
- coordinator_node-0.1.0/coordinator_node/config/runtime.py +29 -0
- coordinator_node-0.1.0/coordinator_node/contracts.py +232 -0
- coordinator_node-0.1.0/coordinator_node/db/__init__.py +6 -0
- coordinator_node-0.1.0/coordinator_node/db/feed_records.py +283 -0
- coordinator_node-0.1.0/coordinator_node/db/init_db.py +90 -0
- coordinator_node-0.1.0/coordinator_node/db/pg_notify.py +59 -0
- coordinator_node-0.1.0/coordinator_node/db/repositories.py +453 -0
- coordinator_node-0.1.0/coordinator_node/db/session.py +21 -0
- coordinator_node-0.1.0/coordinator_node/db/tables/__init__.py +12 -0
- coordinator_node-0.1.0/coordinator_node/db/tables/feed.py +68 -0
- coordinator_node-0.1.0/coordinator_node/db/tables/models.py +50 -0
- coordinator_node-0.1.0/coordinator_node/db/tables/pipeline.py +145 -0
- coordinator_node-0.1.0/coordinator_node/entities/__init__.py +1 -0
- coordinator_node-0.1.0/coordinator_node/entities/feed_record.py +32 -0
- coordinator_node-0.1.0/coordinator_node/entities/model.py +19 -0
- coordinator_node-0.1.0/coordinator_node/entities/prediction.py +118 -0
- coordinator_node-0.1.0/coordinator_node/extensions/__init__.py +1 -0
- coordinator_node-0.1.0/coordinator_node/extensions/callable_resolver.py +42 -0
- coordinator_node-0.1.0/coordinator_node/extensions/default_callables.py +17 -0
- coordinator_node-0.1.0/coordinator_node/feeds/__init__.py +29 -0
- coordinator_node-0.1.0/coordinator_node/feeds/base.py +33 -0
- coordinator_node-0.1.0/coordinator_node/feeds/contracts.py +54 -0
- coordinator_node-0.1.0/coordinator_node/feeds/providers/__init__.py +9 -0
- coordinator_node-0.1.0/coordinator_node/feeds/providers/binance.py +296 -0
- coordinator_node-0.1.0/coordinator_node/feeds/providers/pyth.py +272 -0
- coordinator_node-0.1.0/coordinator_node/feeds/registry.py +81 -0
- coordinator_node-0.1.0/coordinator_node/schemas/__init__.py +15 -0
- coordinator_node-0.1.0/coordinator_node/schemas/payload_contracts.py +76 -0
- coordinator_node-0.1.0/coordinator_node/services/__init__.py +0 -0
- coordinator_node-0.1.0/coordinator_node/services/backfill.py +96 -0
- coordinator_node-0.1.0/coordinator_node/services/feed_data.py +199 -0
- coordinator_node-0.1.0/coordinator_node/services/feed_reader.py +231 -0
- coordinator_node-0.1.0/coordinator_node/services/predict.py +195 -0
- coordinator_node-0.1.0/coordinator_node/services/realtime_predict.py +172 -0
- coordinator_node-0.1.0/coordinator_node/services/score.py +285 -0
- coordinator_node-0.1.0/coordinator_node/workers/__init__.py +1 -0
- coordinator_node-0.1.0/coordinator_node/workers/checkpoint_worker.py +172 -0
- coordinator_node-0.1.0/coordinator_node/workers/feed_data_worker.py +35 -0
- coordinator_node-0.1.0/coordinator_node/workers/predict_worker.py +48 -0
- coordinator_node-0.1.0/coordinator_node/workers/report_worker.py +675 -0
- coordinator_node-0.1.0/coordinator_node/workers/score_worker.py +64 -0
- coordinator_node-0.1.0/docker-compose-local.yml +41 -0
- coordinator_node-0.1.0/docker-compose-prod.yml +54 -0
- coordinator_node-0.1.0/docker-compose.yml +147 -0
- coordinator_node-0.1.0/docs/plans/2026-02-10-coordinator-restructure-design.md +182 -0
- coordinator_node-0.1.0/docs/plans/2026-02-11-contract-based-architecture.md +128 -0
- coordinator_node-0.1.0/docs/plans/2026-02-11-scoring-snapshots-checkpoints.md +126 -0
- coordinator_node-0.1.0/docs/plans/2026-02-11-thin-node-cli-implementation-plan.md +221 -0
- coordinator_node-0.1.0/docs/plans/2026-02-11-thin-node-cli-onboarding-design.md +180 -0
- coordinator_node-0.1.0/mkdocs.yml +25 -0
- coordinator_node-0.1.0/packs/README.md +26 -0
- coordinator_node-0.1.0/pyproject.toml +35 -0
- coordinator_node-0.1.0/scripts/verify_e2e.py +153 -0
- coordinator_node-0.1.0/tests/test_backfill.py +105 -0
- coordinator_node-0.1.0/tests/test_callable_resolver.py +40 -0
- coordinator_node-0.1.0/tests/test_checkpoint_worker.py +401 -0
- coordinator_node-0.1.0/tests/test_coordinator_core_schema.py +65 -0
- coordinator_node-0.1.0/tests/test_coordinator_runtime_data_feeds.py +89 -0
- coordinator_node-0.1.0/tests/test_core_entities.py +53 -0
- coordinator_node-0.1.0/tests/test_node_template_predict_service.py +191 -0
- coordinator_node-0.1.0/tests/test_node_template_report_worker.py +138 -0
- coordinator_node-0.1.0/tests/test_node_template_repositories.py +36 -0
- coordinator_node-0.1.0/tests/test_node_template_score_service.py +245 -0
- coordinator_node-0.1.0/tests/test_prediction_lifecycle.py +470 -0
- coordinator_node-0.1.0/uv.lock +1571 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
POSTGRES_USER=starter
|
|
2
|
+
POSTGRES_PASSWORD=starter
|
|
3
|
+
POSTGRES_DB=starter
|
|
4
|
+
POSTGRES_HOST=localhost
|
|
5
|
+
POSTGRES_PORT=5432
|
|
6
|
+
MODEL_RUNNER_NODE_HOST=localhost
|
|
7
|
+
MODEL_RUNNER_NODE_PORT=9091
|
|
8
|
+
MODEL_RUNNER_TIMEOUT_SECONDS=60
|
|
9
|
+
PROJECT_DIR=.
|
|
10
|
+
|
|
11
|
+
# During development, workers might be launched from the IDE. This allows receiving the model runner IP as localhost.
|
|
12
|
+
MODEL_ORCHESTRATOR_NETWORK=null
|
|
13
|
+
|
|
14
|
+
# Starter profile (BTC + Pyth)
|
|
15
|
+
CRUNCH_ID=starter-challenge
|
|
16
|
+
MODEL_BASE_CLASSNAME=tracker.TrackerBase
|
|
17
|
+
CHECKPOINT_INTERVAL_SECONDS=60
|
|
18
|
+
|
|
19
|
+
INFERENCE_INPUT_BUILDER=node_template.extensions.default_callables:default_build_inference_input
|
|
20
|
+
INFERENCE_OUTPUT_VALIDATOR=node_template.plugins.pyth_updown_btc:validate_probability_up_output
|
|
21
|
+
RAW_INPUT_PROVIDER=node_template.plugins.pyth_updown_btc:build_raw_input_from_pyth
|
|
22
|
+
SCORING_FUNCTION=node_template.plugins.pyth_updown_btc:score_brier_probability_up
|
|
23
|
+
GROUND_TRUTH_RESOLVER=node_template.plugins.pyth_updown_btc:resolve_ground_truth_from_pyth
|
|
24
|
+
MODEL_SCORE_AGGREGATOR=node_template.extensions.default_callables:default_aggregate_model_scores
|
|
25
|
+
LEADERBOARD_RANKER=node_template.extensions.default_callables:default_rank_leaderboard
|
|
26
|
+
|
|
27
|
+
PYTH_HERMES_URL=https://hermes.pyth.network
|
|
28
|
+
PYTH_TIMEOUT_SECONDS=5
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# ── Postgres ──────────────────────────────────────────────
|
|
2
|
+
POSTGRES_USER=starter
|
|
3
|
+
POSTGRES_PASSWORD=starter
|
|
4
|
+
POSTGRES_DB=starter
|
|
5
|
+
POSTGRES_HOST=postgres
|
|
6
|
+
POSTGRES_PORT=5432
|
|
7
|
+
|
|
8
|
+
# ── Competition identity ─────────────────────────────────
|
|
9
|
+
CRUNCH_ID=starter-challenge
|
|
10
|
+
# CRUNCH_PUBKEY= # on-chain crunch address (for emissions)
|
|
11
|
+
|
|
12
|
+
# ── Model runner ─────────────────────────────────────────
|
|
13
|
+
MODEL_RUNNER_NODE_HOST=model-orchestrator
|
|
14
|
+
MODEL_RUNNER_NODE_PORT=9091
|
|
15
|
+
MODEL_RUNNER_TIMEOUT_SECONDS=60
|
|
16
|
+
MODEL_BASE_CLASSNAME=tracker.TrackerBase
|
|
17
|
+
|
|
18
|
+
# ── Feed (data source) ──────────────────────────────────
|
|
19
|
+
FEED_SOURCE=pyth
|
|
20
|
+
FEED_SUBJECTS=BTC
|
|
21
|
+
FEED_KIND=tick
|
|
22
|
+
FEED_GRANULARITY=1s
|
|
23
|
+
FEED_POLL_SECONDS=5
|
|
24
|
+
FEED_BACKFILL_MINUTES=180
|
|
25
|
+
FEED_CANDLES_WINDOW=120
|
|
26
|
+
FEED_RECORD_TTL_DAYS=90
|
|
27
|
+
# FEED_RETENTION_CHECK_SECONDS=3600
|
|
28
|
+
|
|
29
|
+
# ── Scoring ──────────────────────────────────────────────
|
|
30
|
+
SCORING_FUNCTION=coordinator_node.extensions.default_callables:default_score_prediction
|
|
31
|
+
CHECKPOINT_INTERVAL_SECONDS=60
|
|
32
|
+
|
|
33
|
+
# ── Checkpoint / Emissions ───────────────────────────────
|
|
34
|
+
# CHECKPOINT_INTERVAL_SECONDS=604800 # weekly (default)
|
|
35
|
+
# COMPUTE_PROVIDER_PUBKEY= # wallet pubkey for compute provider rewards
|
|
36
|
+
# DATA_PROVIDER_PUBKEY= # wallet pubkey for data provider rewards
|
|
37
|
+
|
|
38
|
+
# ── Pyth-specific ────────────────────────────────────────
|
|
39
|
+
PYTH_HERMES_URL=https://hermes.pyth.network
|
|
40
|
+
PYTH_TIMEOUT_SECONDS=5
|
|
41
|
+
|
|
42
|
+
# ── Scheduled predictions (optional) ─────────────────────
|
|
43
|
+
# SCHEDULED_PREDICTION_CONFIGS_PATH=config/scheduled_predictions.json
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# ── Postgres ──────────────────────────────────────────────
|
|
2
|
+
POSTGRES_USER=<CHANGE_ME>
|
|
3
|
+
POSTGRES_PASSWORD=<CHANGE_ME>
|
|
4
|
+
POSTGRES_DB=<CHANGE_ME>
|
|
5
|
+
POSTGRES_HOST=postgres
|
|
6
|
+
POSTGRES_PORT=5432
|
|
7
|
+
# READONLY_USER_PASSWORD=<CHANGE_ME>
|
|
8
|
+
|
|
9
|
+
# ── Competition identity ─────────────────────────────────
|
|
10
|
+
CRUNCH_ID=<CHANGE_ME>
|
|
11
|
+
CRUNCH_PUBKEY=<CHANGE_ME>
|
|
12
|
+
|
|
13
|
+
# ── Model runner ─────────────────────────────────────────
|
|
14
|
+
MODEL_RUNNER_NODE_HOST=model-orchestrator
|
|
15
|
+
MODEL_RUNNER_NODE_PORT=9091
|
|
16
|
+
MODEL_RUNNER_TIMEOUT_SECONDS=60
|
|
17
|
+
MODEL_BASE_CLASSNAME=tracker.TrackerBase
|
|
18
|
+
|
|
19
|
+
# ── Feed (data source) ──────────────────────────────────
|
|
20
|
+
FEED_SOURCE=pyth
|
|
21
|
+
FEED_SUBJECTS=BTC
|
|
22
|
+
FEED_KIND=tick
|
|
23
|
+
FEED_GRANULARITY=1s
|
|
24
|
+
FEED_POLL_SECONDS=5
|
|
25
|
+
FEED_BACKFILL_MINUTES=180
|
|
26
|
+
FEED_CANDLES_WINDOW=120
|
|
27
|
+
FEED_RECORD_TTL_DAYS=90
|
|
28
|
+
|
|
29
|
+
# ── Scoring ──────────────────────────────────────────────
|
|
30
|
+
SCORING_FUNCTION=coordinator_node.extensions.default_callables:default_score_prediction
|
|
31
|
+
|
|
32
|
+
# ── Checkpoint / Emissions ───────────────────────────────
|
|
33
|
+
CHECKPOINT_INTERVAL_SECONDS=604800
|
|
34
|
+
# COMPUTE_PROVIDER_PUBKEY=<CHANGE_ME>
|
|
35
|
+
# DATA_PROVIDER_PUBKEY=<CHANGE_ME>
|
|
36
|
+
|
|
37
|
+
# ── Pyth-specific ────────────────────────────────────────
|
|
38
|
+
PYTH_HERMES_URL=https://hermes.pyth.network
|
|
39
|
+
PYTH_TIMEOUT_SECONDS=5
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
|
3
|
+
|
|
4
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
5
|
+
libpq5 \
|
|
6
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
7
|
+
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
COPY pyproject.toml ./
|
|
11
|
+
RUN uv sync --no-install-project
|
|
12
|
+
|
|
13
|
+
ENV VIRTUAL_ENV=/app/.venv
|
|
14
|
+
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
|
15
|
+
|
|
16
|
+
COPY coordinator_node ./coordinator_node
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
COMPOSE := docker compose -f docker-compose.yml --env-file .local.env
|
|
2
|
+
|
|
3
|
+
.PHONY: deploy down logs test
|
|
4
|
+
|
|
5
|
+
deploy:
|
|
6
|
+
$(COMPOSE) up -d --build
|
|
7
|
+
|
|
8
|
+
down:
|
|
9
|
+
$(COMPOSE) down
|
|
10
|
+
|
|
11
|
+
logs:
|
|
12
|
+
$(COMPOSE) logs -f
|
|
13
|
+
|
|
14
|
+
test:
|
|
15
|
+
uv run python -m pytest tests/ -x -q
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coordinator-node
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Runtime engine for Crunch coordinator nodes
|
|
5
|
+
Project-URL: Homepage, https://github.com/crunchdao/coordinator-node-starter
|
|
6
|
+
Project-URL: Repository, https://github.com/crunchdao/coordinator-node-starter
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: fastapi>=0.100.0
|
|
10
|
+
Requires-Dist: model-runner-client>=0.10.0
|
|
11
|
+
Requires-Dist: psycopg2-binary>=2.9
|
|
12
|
+
Requires-Dist: python-binance>=1.0
|
|
13
|
+
Requires-Dist: requests>=2.28
|
|
14
|
+
Requires-Dist: sqlmodel>=0.0.14
|
|
15
|
+
Requires-Dist: uvicorn>=0.20
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# crunch-node
|
|
19
|
+
|
|
20
|
+
Runtime engine for Crunch coordinator nodes. Published as `crunch-node` on PyPI, imported as `coordinator_node`.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install crunch-node
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
|
|
28
|
+
### Pipeline
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Feed → Input → Prediction → Score → Snapshot → Checkpoint → On-chain
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Workers:**
|
|
35
|
+
|
|
36
|
+
| Worker | Purpose |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `feed-data-worker` | Ingests feed data (Pyth, Binance, etc.) via WebSocket + backfill |
|
|
39
|
+
| `predict-worker` | Event-driven: gets data → ticks models → collects predictions |
|
|
40
|
+
| `score-worker` | Resolves actuals → scores predictions → writes snapshots → rebuilds leaderboard |
|
|
41
|
+
| `checkpoint-worker` | Aggregates snapshots → builds EmissionCheckpoint for on-chain submission |
|
|
42
|
+
| `report-worker` | FastAPI: leaderboard, predictions, feeds, snapshots, checkpoints, emissions |
|
|
43
|
+
|
|
44
|
+
### Contract
|
|
45
|
+
|
|
46
|
+
All type shapes and behavior are defined in a single `CrunchContract`:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from coordinator_node.contracts import CrunchContract
|
|
50
|
+
|
|
51
|
+
class CrunchContract(BaseModel):
|
|
52
|
+
raw_input_type: type[BaseModel] = RawInput
|
|
53
|
+
output_type: type[BaseModel] = InferenceOutput
|
|
54
|
+
score_type: type[BaseModel] = ScoreResult
|
|
55
|
+
scope: PredictionScope = PredictionScope()
|
|
56
|
+
aggregation: Aggregation = Aggregation()
|
|
57
|
+
|
|
58
|
+
# Callables
|
|
59
|
+
resolve_ground_truth: Callable = default_resolve_ground_truth
|
|
60
|
+
aggregate_snapshot: Callable = default_aggregate_snapshot
|
|
61
|
+
build_emission: Callable = default_build_emission
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Feed Dimensions
|
|
65
|
+
|
|
66
|
+
| Dimension | Example | Env var |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `source` | pyth, binance | `FEED_SOURCE` |
|
|
69
|
+
| `subject` | BTC, ETH | `FEED_SUBJECTS` |
|
|
70
|
+
| `kind` | tick, candle | `FEED_KIND` |
|
|
71
|
+
| `granularity` | 1s, 1m | `FEED_GRANULARITY` |
|
|
72
|
+
|
|
73
|
+
### Status Lifecycles
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Input: RECEIVED → RESOLVED
|
|
77
|
+
Prediction: PENDING → SCORED / FAILED / ABSENT
|
|
78
|
+
Checkpoint: PENDING → SUBMITTED → CLAIMABLE → PAID
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Emission Checkpoints
|
|
82
|
+
|
|
83
|
+
Checkpoints produce `EmissionCheckpoint` matching the on-chain protocol:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
{
|
|
87
|
+
"crunch": "<pubkey>",
|
|
88
|
+
"cruncher_rewards": [{"cruncher_index": 0, "reward_pct": 350_000_000}, ...],
|
|
89
|
+
"compute_provider_rewards": [...],
|
|
90
|
+
"data_provider_rewards": [...],
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`reward_pct` uses frac64 (1,000,000,000 = 100%).
|
|
95
|
+
|
|
96
|
+
### Report API
|
|
97
|
+
|
|
98
|
+
| Endpoint | Description |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `GET /reports/leaderboard` | Current leaderboard |
|
|
101
|
+
| `GET /reports/models` | Registered models |
|
|
102
|
+
| `GET /reports/predictions` | Prediction history |
|
|
103
|
+
| `GET /reports/feeds` | Active feed subscriptions |
|
|
104
|
+
| `GET /reports/snapshots` | Per-model period summaries |
|
|
105
|
+
| `GET /reports/checkpoints` | Checkpoint history |
|
|
106
|
+
| `GET /reports/checkpoints/{id}/emission` | Raw emission (frac64) |
|
|
107
|
+
| `GET /reports/checkpoints/{id}/emission/cli-format` | CLI JSON format |
|
|
108
|
+
| `GET /reports/emissions/latest` | Latest emission |
|
|
109
|
+
| `POST /reports/checkpoints/{id}/confirm` | Record tx_hash |
|
|
110
|
+
| `PATCH /reports/checkpoints/{id}/status` | Advance status |
|
|
111
|
+
|
|
112
|
+
## Scaffolding
|
|
113
|
+
|
|
114
|
+
Use `crunch-cli init-workspace <name>` to create a new competition workspace from the `base/` template.
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv run pytest tests/ -q
|
|
120
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# crunch-node
|
|
2
|
+
|
|
3
|
+
Runtime engine for Crunch coordinator nodes. Published as `crunch-node` on PyPI, imported as `coordinator_node`.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install crunch-node
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### Pipeline
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Feed → Input → Prediction → Score → Snapshot → Checkpoint → On-chain
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Workers:**
|
|
18
|
+
|
|
19
|
+
| Worker | Purpose |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `feed-data-worker` | Ingests feed data (Pyth, Binance, etc.) via WebSocket + backfill |
|
|
22
|
+
| `predict-worker` | Event-driven: gets data → ticks models → collects predictions |
|
|
23
|
+
| `score-worker` | Resolves actuals → scores predictions → writes snapshots → rebuilds leaderboard |
|
|
24
|
+
| `checkpoint-worker` | Aggregates snapshots → builds EmissionCheckpoint for on-chain submission |
|
|
25
|
+
| `report-worker` | FastAPI: leaderboard, predictions, feeds, snapshots, checkpoints, emissions |
|
|
26
|
+
|
|
27
|
+
### Contract
|
|
28
|
+
|
|
29
|
+
All type shapes and behavior are defined in a single `CrunchContract`:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from coordinator_node.contracts import CrunchContract
|
|
33
|
+
|
|
34
|
+
class CrunchContract(BaseModel):
|
|
35
|
+
raw_input_type: type[BaseModel] = RawInput
|
|
36
|
+
output_type: type[BaseModel] = InferenceOutput
|
|
37
|
+
score_type: type[BaseModel] = ScoreResult
|
|
38
|
+
scope: PredictionScope = PredictionScope()
|
|
39
|
+
aggregation: Aggregation = Aggregation()
|
|
40
|
+
|
|
41
|
+
# Callables
|
|
42
|
+
resolve_ground_truth: Callable = default_resolve_ground_truth
|
|
43
|
+
aggregate_snapshot: Callable = default_aggregate_snapshot
|
|
44
|
+
build_emission: Callable = default_build_emission
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Feed Dimensions
|
|
48
|
+
|
|
49
|
+
| Dimension | Example | Env var |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `source` | pyth, binance | `FEED_SOURCE` |
|
|
52
|
+
| `subject` | BTC, ETH | `FEED_SUBJECTS` |
|
|
53
|
+
| `kind` | tick, candle | `FEED_KIND` |
|
|
54
|
+
| `granularity` | 1s, 1m | `FEED_GRANULARITY` |
|
|
55
|
+
|
|
56
|
+
### Status Lifecycles
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Input: RECEIVED → RESOLVED
|
|
60
|
+
Prediction: PENDING → SCORED / FAILED / ABSENT
|
|
61
|
+
Checkpoint: PENDING → SUBMITTED → CLAIMABLE → PAID
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Emission Checkpoints
|
|
65
|
+
|
|
66
|
+
Checkpoints produce `EmissionCheckpoint` matching the on-chain protocol:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
{
|
|
70
|
+
"crunch": "<pubkey>",
|
|
71
|
+
"cruncher_rewards": [{"cruncher_index": 0, "reward_pct": 350_000_000}, ...],
|
|
72
|
+
"compute_provider_rewards": [...],
|
|
73
|
+
"data_provider_rewards": [...],
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`reward_pct` uses frac64 (1,000,000,000 = 100%).
|
|
78
|
+
|
|
79
|
+
### Report API
|
|
80
|
+
|
|
81
|
+
| Endpoint | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `GET /reports/leaderboard` | Current leaderboard |
|
|
84
|
+
| `GET /reports/models` | Registered models |
|
|
85
|
+
| `GET /reports/predictions` | Prediction history |
|
|
86
|
+
| `GET /reports/feeds` | Active feed subscriptions |
|
|
87
|
+
| `GET /reports/snapshots` | Per-model period summaries |
|
|
88
|
+
| `GET /reports/checkpoints` | Checkpoint history |
|
|
89
|
+
| `GET /reports/checkpoints/{id}/emission` | Raw emission (frac64) |
|
|
90
|
+
| `GET /reports/checkpoints/{id}/emission/cli-format` | CLI JSON format |
|
|
91
|
+
| `GET /reports/emissions/latest` | Latest emission |
|
|
92
|
+
| `POST /reports/checkpoints/{id}/confirm` | Record tx_hash |
|
|
93
|
+
| `PATCH /reports/checkpoints/{id}/status` | Advance status |
|
|
94
|
+
|
|
95
|
+
## Scaffolding
|
|
96
|
+
|
|
97
|
+
Use `crunch-cli init-workspace <name>` to create a new competition workspace from the `base/` template.
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv run pytest tests/ -q
|
|
103
|
+
```
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coordinator-node-starter
|
|
3
|
+
description: Use when creating or customizing a Crunch coordinator node from this template repository and defining competition contracts before implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Coordinator Node Starter
|
|
7
|
+
|
|
8
|
+
Use this repository as the **base template source** for new Crunch coordinator nodes.
|
|
9
|
+
|
|
10
|
+
- This repo provides: `coordinator_core/` + `node_template/`
|
|
11
|
+
- You create: `crunch-<name>` (public package) and `crunch-node-<name>` (private runnable node)
|
|
12
|
+
- The coordinator agent should guide users through required design decisions before code changes
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Template Usage Model (Required)
|
|
17
|
+
|
|
18
|
+
When the user wants a new Crunch, use the CLI-first scaffold flow:
|
|
19
|
+
|
|
20
|
+
1. Create an upfront answers file (JSON/YAML) for deterministic setup decisions.
|
|
21
|
+
2. Run preflight to halt on busy local ports.
|
|
22
|
+
3. Run `coordinator init` (with `--answers` and optional `--spec`).
|
|
23
|
+
4. Implement challenge logic in generated `crunch-<name>`.
|
|
24
|
+
5. Run generated node verification flow in `crunch-node-<name>`.
|
|
25
|
+
|
|
26
|
+
Reference: `docs/flow.md`.
|
|
27
|
+
|
|
28
|
+
This repository is the **template and contract baseline**, not the long-term identity of a specific Crunch.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Required Crunch Definition (Must Be Explicit)
|
|
33
|
+
|
|
34
|
+
Before implementation, the agent must help the user define and validate these six points:
|
|
35
|
+
|
|
36
|
+
1. **Define Model Interface**
|
|
37
|
+
2. **Define inference input**
|
|
38
|
+
3. **Define inference output**
|
|
39
|
+
4. **Define scoring function**
|
|
40
|
+
5. **Define ModelScore**
|
|
41
|
+
6. **Define checkpoint interval**
|
|
42
|
+
|
|
43
|
+
If any point is missing, stop implementation and ask follow-up questions.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Competition Design Checklist (Conversation Flow)
|
|
48
|
+
|
|
49
|
+
### 0. Project Name (ask first)
|
|
50
|
+
Ask:
|
|
51
|
+
> What should we call this Crunch? (used for `crunch-<name>` and `crunch-node-<name>`)
|
|
52
|
+
|
|
53
|
+
### 1. Define Model Interface
|
|
54
|
+
Ask:
|
|
55
|
+
> What methods must participant models implement, and what are runtime constraints (timeout, state, allowed libs)?
|
|
56
|
+
|
|
57
|
+
Output required:
|
|
58
|
+
- base class contract in `crunch-<name>`
|
|
59
|
+
- model runner `base_classname` to configure in node runtime
|
|
60
|
+
|
|
61
|
+
### 2. Define inference input
|
|
62
|
+
Ask:
|
|
63
|
+
> What raw data enters the system, and what transformed payload is sent to models?
|
|
64
|
+
|
|
65
|
+
Output required:
|
|
66
|
+
- input builder callable signature: `build_input(raw_input) -> dict`
|
|
67
|
+
- optional schema artifact in `crunch-<name>`
|
|
68
|
+
|
|
69
|
+
### 3. Define inference output
|
|
70
|
+
Ask:
|
|
71
|
+
> What should `predict` return (shape, length, validation rules, failure rules)?
|
|
72
|
+
|
|
73
|
+
Output required:
|
|
74
|
+
- output contract in `crunch-<name>`
|
|
75
|
+
- validator callable signature: `validate_output(inference_output) -> dict`
|
|
76
|
+
|
|
77
|
+
### 4. Define scoring function
|
|
78
|
+
Ask:
|
|
79
|
+
> How are predictions scored against ground truth, and how are invalid outputs handled?
|
|
80
|
+
|
|
81
|
+
Output required:
|
|
82
|
+
- scoring callable signature: `score_prediction(prediction, ground_truth) -> {value, success, failed_reason}`
|
|
83
|
+
- callable path in node config: `SCORING_FUNCTION=...`
|
|
84
|
+
|
|
85
|
+
### 5. Define ModelScore
|
|
86
|
+
Ask:
|
|
87
|
+
> How should per-model performance be aggregated and represented?
|
|
88
|
+
|
|
89
|
+
Output required:
|
|
90
|
+
- model-score aggregator callable signature: `aggregate_model_scores(scored_predictions, models) -> list[dict]`
|
|
91
|
+
- JSON-serializable score payload strategy (`score_payload_jsonb`)
|
|
92
|
+
|
|
93
|
+
### 6. Define checkpoint interval
|
|
94
|
+
Ask:
|
|
95
|
+
> What scoring/predict loop interval do you want for this Crunch node?
|
|
96
|
+
|
|
97
|
+
Output required:
|
|
98
|
+
- `CHECKPOINT_INTERVAL_SECONDS` value for `crunch-node-<name>`
|
|
99
|
+
- rationale for cadence vs cost/latency
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Where To Implement In This Structure
|
|
104
|
+
|
|
105
|
+
### Stable core contracts
|
|
106
|
+
- `coordinator_core/infrastructure/db/db_tables.py`
|
|
107
|
+
- `coordinator_core/entities/*`
|
|
108
|
+
- `coordinator_core/services/interfaces/*`
|
|
109
|
+
|
|
110
|
+
### Default runtime template
|
|
111
|
+
- `node_template/workers/*`
|
|
112
|
+
- `node_template/services/*`
|
|
113
|
+
- `node_template/infrastructure/db/*`
|
|
114
|
+
- `node_template/config/extensions.py`
|
|
115
|
+
- `node_template/config/runtime.py`
|
|
116
|
+
- `node_template/extensions/default_callables.py`
|
|
117
|
+
|
|
118
|
+
Current operational defaults in this template:
|
|
119
|
+
- `predict-worker` and `score-worker` configure INFO logging and emit lifecycle/idle logs.
|
|
120
|
+
- `ScoreService` attempts repository rollbacks on loop exceptions (where `rollback()` is available).
|
|
121
|
+
|
|
122
|
+
### Crunch-specific extension points
|
|
123
|
+
Set callable paths in env/config:
|
|
124
|
+
- `INFERENCE_INPUT_BUILDER`
|
|
125
|
+
- `INFERENCE_OUTPUT_VALIDATOR`
|
|
126
|
+
- `SCORING_FUNCTION`
|
|
127
|
+
- `MODEL_SCORE_AGGREGATOR`
|
|
128
|
+
- `LEADERBOARD_RANKER`
|
|
129
|
+
- `CHECKPOINT_INTERVAL_SECONDS`
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Post-Deployment Verification (Mandatory)
|
|
134
|
+
|
|
135
|
+
After any change, run (from generated `crunch-node-<name>`):
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# 1) Optional preflight from repo root
|
|
139
|
+
coordinator preflight --ports 3000,5432,8000,9091
|
|
140
|
+
|
|
141
|
+
# 2) Rebuild + start
|
|
142
|
+
make deploy
|
|
143
|
+
|
|
144
|
+
# 3) E2E verification
|
|
145
|
+
make verify-e2e
|
|
146
|
+
|
|
147
|
+
# 4) Structured runtime log capture for analysis
|
|
148
|
+
make logs-capture
|
|
149
|
+
|
|
150
|
+
# 5) Basic API checks
|
|
151
|
+
curl -s http://localhost:8000/healthz
|
|
152
|
+
curl -s http://localhost:8000/reports/models
|
|
153
|
+
curl -s http://localhost:8000/reports/leaderboard
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Artifacts to inspect:
|
|
157
|
+
- `RUNBOOK.md` (generated in node workspace)
|
|
158
|
+
- `runtime-services.jsonl` (from `make logs-capture`)
|
|
159
|
+
- `process-log.jsonl` (generated in workspace root)
|
|
160
|
+
|
|
161
|
+
Do not declare completion if verification fails.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Sub-skills
|
|
166
|
+
|
|
167
|
+
Use these focused skills when needed:
|
|
168
|
+
|
|
169
|
+
- `coordinator-data-sources` → customize data feeds / inference input sources
|
|
170
|
+
- `coordinator-prediction-format` → customize inference input/output contracts
|
|
171
|
+
- `coordinator-scoring` → customize scoring + ModelScore aggregation
|
|
172
|
+
- `coordinator-leaderboard-reports` → customize ranking and report endpoints
|
|
173
|
+
|
|
174
|
+
(These skill files remain at their existing repository paths for compatibility with the agent harness.)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Workspace-level convenience — proxies to node/
|
|
2
|
+
.PHONY: deploy down logs verify-e2e check-models
|
|
3
|
+
|
|
4
|
+
deploy:
|
|
5
|
+
cd node && make deploy
|
|
6
|
+
|
|
7
|
+
down:
|
|
8
|
+
cd node && make down
|
|
9
|
+
|
|
10
|
+
logs:
|
|
11
|
+
cd node && make logs
|
|
12
|
+
|
|
13
|
+
verify-e2e:
|
|
14
|
+
cd node && make verify-e2e
|
|
15
|
+
|
|
16
|
+
check-models:
|
|
17
|
+
cd node && make check-models
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# starter-challenge
|
|
2
|
+
|
|
3
|
+
Coordinator workspace. Run from `node/`:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd node
|
|
7
|
+
make deploy
|
|
8
|
+
make verify-e2e
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
|
|
13
|
+
- `node/` — competition infrastructure (docker-compose, config, scripts)
|
|
14
|
+
- `challenge/` — participant-facing package (tracker, scoring, examples)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: starter-challenge-workspace
|
|
3
|
+
summary: Agent runbook for this generated Crunch workspace.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# starter-challenge workspace skill
|
|
7
|
+
|
|
8
|
+
## Fast path (from workspace root)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
cd node
|
|
12
|
+
make deploy
|
|
13
|
+
make verify-e2e
|
|
14
|
+
make logs-capture
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Where logs and diagnostics live
|
|
18
|
+
|
|
19
|
+
- Live service logs: `cd node && make logs`
|
|
20
|
+
- Captured runtime logs: `node/runtime-services.jsonl`
|
|
21
|
+
- Lifecycle audit: `process-log.jsonl`
|
|
22
|
+
- Additional troubleshooting: `node/RUNBOOK.md`
|
|
23
|
+
|
|
24
|
+
## Where to edit code
|
|
25
|
+
|
|
26
|
+
- **Challenge behavior** (tracker, scoring, examples):
|
|
27
|
+
`challenge/starter_challenge/`
|
|
28
|
+
- **Runtime contract** (types, callables, emission config):
|
|
29
|
+
`node/runtime_definitions/contracts.py`
|
|
30
|
+
- **Node config** (.env, deployment, schedules):
|
|
31
|
+
`node/`
|
|
32
|
+
|
|
33
|
+
## Validation after changes
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd node
|
|
37
|
+
make verify-e2e
|
|
38
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# challenge
|
|
2
|
+
|
|
3
|
+
Public challenge package.
|
|
4
|
+
|
|
5
|
+
Primary package: `starter_challenge`
|
|
6
|
+
|
|
7
|
+
Implement participant-facing files in:
|
|
8
|
+
|
|
9
|
+
- `tracker.py`
|
|
10
|
+
- `scoring.py`
|
|
11
|
+
- `examples/mean_reversion_tracker.py`
|
|
12
|
+
- `examples/trend_following_tracker.py`
|
|
13
|
+
- `examples/volatility_regime_tracker.py`
|
|
14
|
+
|
|
15
|
+
Node-private runtime callables live in:
|
|
16
|
+
|
|
17
|
+
- `../node/runtime_definitions/`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: starter-challenge-challenge
|
|
3
|
+
summary: Agent instructions for implementing challenge logic.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Challenge skill - challenge
|
|
7
|
+
|
|
8
|
+
## Primary implementation files
|
|
9
|
+
|
|
10
|
+
- `starter_challenge/tracker.py` — model interface (participants implement this)
|
|
11
|
+
- `starter_challenge/scoring.py` — scoring function for local self-eval
|
|
12
|
+
- `starter_challenge/examples/` — quickstarter implementations
|
|
13
|
+
|
|
14
|
+
## Runtime contract (node-private)
|
|
15
|
+
|
|
16
|
+
- `../node/runtime_definitions/contracts.py` — CrunchContract defining types, scoring, emission
|
|
17
|
+
|
|
18
|
+
## Development guidance
|
|
19
|
+
|
|
20
|
+
- Keep participant-facing challenge logic in this package.
|
|
21
|
+
- Keep runtime contracts and deployment config in `../node/`.
|
|
22
|
+
- The scoring function in `scoring.py` is used for local self-eval.
|
|
23
|
+
The runtime scoring callable is configured in `contracts.py`.
|
|
24
|
+
|
|
25
|
+
## Validate from node workspace
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd ../node
|
|
29
|
+
make verify-e2e
|
|
30
|
+
```
|