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.
Files changed (126) hide show
  1. coordinator_node-0.1.0/.dev.env +28 -0
  2. coordinator_node-0.1.0/.dockerignore +2 -0
  3. coordinator_node-0.1.0/.gitignore +18 -0
  4. coordinator_node-0.1.0/.local.env +43 -0
  5. coordinator_node-0.1.0/.production.env +39 -0
  6. coordinator_node-0.1.0/.python-version +1 -0
  7. coordinator_node-0.1.0/Dockerfile +16 -0
  8. coordinator_node-0.1.0/Makefile +15 -0
  9. coordinator_node-0.1.0/PKG-INFO +120 -0
  10. coordinator_node-0.1.0/README.md +103 -0
  11. coordinator_node-0.1.0/SKILL.md +174 -0
  12. coordinator_node-0.1.0/base/Makefile +17 -0
  13. coordinator_node-0.1.0/base/README.md +14 -0
  14. coordinator_node-0.1.0/base/SKILL.md +38 -0
  15. coordinator_node-0.1.0/base/challenge/README.md +17 -0
  16. coordinator_node-0.1.0/base/challenge/SKILL.md +30 -0
  17. coordinator_node-0.1.0/base/challenge/pyproject.toml +14 -0
  18. coordinator_node-0.1.0/base/challenge/starter_challenge/__init__.py +3 -0
  19. coordinator_node-0.1.0/base/challenge/starter_challenge/examples/README.md +9 -0
  20. coordinator_node-0.1.0/base/challenge/starter_challenge/examples/__init__.py +9 -0
  21. coordinator_node-0.1.0/base/challenge/starter_challenge/examples/mean_reversion_tracker.py +58 -0
  22. coordinator_node-0.1.0/base/challenge/starter_challenge/examples/trend_following_tracker.py +57 -0
  23. coordinator_node-0.1.0/base/challenge/starter_challenge/examples/volatility_regime_tracker.py +84 -0
  24. coordinator_node-0.1.0/base/challenge/starter_challenge/schemas/README.md +5 -0
  25. coordinator_node-0.1.0/base/challenge/starter_challenge/scoring.py +10 -0
  26. coordinator_node-0.1.0/base/challenge/starter_challenge/tracker.py +11 -0
  27. coordinator_node-0.1.0/base/node/.local.env +48 -0
  28. coordinator_node-0.1.0/base/node/.local.env.example +30 -0
  29. coordinator_node-0.1.0/base/node/.production.env.example +39 -0
  30. coordinator_node-0.1.0/base/node/Dockerfile +26 -0
  31. coordinator_node-0.1.0/base/node/Makefile +51 -0
  32. coordinator_node-0.1.0/base/node/README.md +22 -0
  33. coordinator_node-0.1.0/base/node/RUNBOOK.md +45 -0
  34. coordinator_node-0.1.0/base/node/SKILL.md +53 -0
  35. coordinator_node-0.1.0/base/node/config/README.md +4 -0
  36. coordinator_node-0.1.0/base/node/config/callables.env +1 -0
  37. coordinator_node-0.1.0/base/node/config/scheduled_prediction_configs.json +11 -0
  38. coordinator_node-0.1.0/base/node/deployment/README.md +6 -0
  39. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/docker-entrypoint.sh +18 -0
  40. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/models.dev.yml +8 -0
  41. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/orchestrator.dev.yml +33 -0
  42. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/main.py +8 -0
  43. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/requirements.txt +1 -0
  44. coordinator_node-0.1.0/base/node/deployment/model-orchestrator-local/config/starter-submission/tracker.py +18 -0
  45. coordinator_node-0.1.0/base/node/deployment/report-ui/config/global-settings.json +15 -0
  46. coordinator_node-0.1.0/base/node/deployment/report-ui/config/leaderboard-columns.json +45 -0
  47. coordinator_node-0.1.0/base/node/deployment/report-ui/config/metrics-widgets.json +123 -0
  48. coordinator_node-0.1.0/base/node/docker-compose.yml +233 -0
  49. coordinator_node-0.1.0/base/node/extensions/README.md +10 -0
  50. coordinator_node-0.1.0/base/node/plugins/README.md +18 -0
  51. coordinator_node-0.1.0/base/node/pyproject.toml +11 -0
  52. coordinator_node-0.1.0/base/node/runtime_definitions/__init__.py +1 -0
  53. coordinator_node-0.1.0/base/node/runtime_definitions/contracts.py +222 -0
  54. coordinator_node-0.1.0/base/node/scripts/backfill.py +93 -0
  55. coordinator_node-0.1.0/base/node/scripts/capture_runtime_logs.py +73 -0
  56. coordinator_node-0.1.0/base/node/scripts/check_models.py +99 -0
  57. coordinator_node-0.1.0/base/node/scripts/verify_e2e.py +138 -0
  58. coordinator_node-0.1.0/clean-data.sh +7 -0
  59. coordinator_node-0.1.0/coordinator_node/__init__.py +0 -0
  60. coordinator_node-0.1.0/coordinator_node/config/__init__.py +1 -0
  61. coordinator_node-0.1.0/coordinator_node/config/extensions.py +18 -0
  62. coordinator_node-0.1.0/coordinator_node/config/runtime.py +29 -0
  63. coordinator_node-0.1.0/coordinator_node/contracts.py +232 -0
  64. coordinator_node-0.1.0/coordinator_node/db/__init__.py +6 -0
  65. coordinator_node-0.1.0/coordinator_node/db/feed_records.py +283 -0
  66. coordinator_node-0.1.0/coordinator_node/db/init_db.py +90 -0
  67. coordinator_node-0.1.0/coordinator_node/db/pg_notify.py +59 -0
  68. coordinator_node-0.1.0/coordinator_node/db/repositories.py +453 -0
  69. coordinator_node-0.1.0/coordinator_node/db/session.py +21 -0
  70. coordinator_node-0.1.0/coordinator_node/db/tables/__init__.py +12 -0
  71. coordinator_node-0.1.0/coordinator_node/db/tables/feed.py +68 -0
  72. coordinator_node-0.1.0/coordinator_node/db/tables/models.py +50 -0
  73. coordinator_node-0.1.0/coordinator_node/db/tables/pipeline.py +145 -0
  74. coordinator_node-0.1.0/coordinator_node/entities/__init__.py +1 -0
  75. coordinator_node-0.1.0/coordinator_node/entities/feed_record.py +32 -0
  76. coordinator_node-0.1.0/coordinator_node/entities/model.py +19 -0
  77. coordinator_node-0.1.0/coordinator_node/entities/prediction.py +118 -0
  78. coordinator_node-0.1.0/coordinator_node/extensions/__init__.py +1 -0
  79. coordinator_node-0.1.0/coordinator_node/extensions/callable_resolver.py +42 -0
  80. coordinator_node-0.1.0/coordinator_node/extensions/default_callables.py +17 -0
  81. coordinator_node-0.1.0/coordinator_node/feeds/__init__.py +29 -0
  82. coordinator_node-0.1.0/coordinator_node/feeds/base.py +33 -0
  83. coordinator_node-0.1.0/coordinator_node/feeds/contracts.py +54 -0
  84. coordinator_node-0.1.0/coordinator_node/feeds/providers/__init__.py +9 -0
  85. coordinator_node-0.1.0/coordinator_node/feeds/providers/binance.py +296 -0
  86. coordinator_node-0.1.0/coordinator_node/feeds/providers/pyth.py +272 -0
  87. coordinator_node-0.1.0/coordinator_node/feeds/registry.py +81 -0
  88. coordinator_node-0.1.0/coordinator_node/schemas/__init__.py +15 -0
  89. coordinator_node-0.1.0/coordinator_node/schemas/payload_contracts.py +76 -0
  90. coordinator_node-0.1.0/coordinator_node/services/__init__.py +0 -0
  91. coordinator_node-0.1.0/coordinator_node/services/backfill.py +96 -0
  92. coordinator_node-0.1.0/coordinator_node/services/feed_data.py +199 -0
  93. coordinator_node-0.1.0/coordinator_node/services/feed_reader.py +231 -0
  94. coordinator_node-0.1.0/coordinator_node/services/predict.py +195 -0
  95. coordinator_node-0.1.0/coordinator_node/services/realtime_predict.py +172 -0
  96. coordinator_node-0.1.0/coordinator_node/services/score.py +285 -0
  97. coordinator_node-0.1.0/coordinator_node/workers/__init__.py +1 -0
  98. coordinator_node-0.1.0/coordinator_node/workers/checkpoint_worker.py +172 -0
  99. coordinator_node-0.1.0/coordinator_node/workers/feed_data_worker.py +35 -0
  100. coordinator_node-0.1.0/coordinator_node/workers/predict_worker.py +48 -0
  101. coordinator_node-0.1.0/coordinator_node/workers/report_worker.py +675 -0
  102. coordinator_node-0.1.0/coordinator_node/workers/score_worker.py +64 -0
  103. coordinator_node-0.1.0/docker-compose-local.yml +41 -0
  104. coordinator_node-0.1.0/docker-compose-prod.yml +54 -0
  105. coordinator_node-0.1.0/docker-compose.yml +147 -0
  106. coordinator_node-0.1.0/docs/plans/2026-02-10-coordinator-restructure-design.md +182 -0
  107. coordinator_node-0.1.0/docs/plans/2026-02-11-contract-based-architecture.md +128 -0
  108. coordinator_node-0.1.0/docs/plans/2026-02-11-scoring-snapshots-checkpoints.md +126 -0
  109. coordinator_node-0.1.0/docs/plans/2026-02-11-thin-node-cli-implementation-plan.md +221 -0
  110. coordinator_node-0.1.0/docs/plans/2026-02-11-thin-node-cli-onboarding-design.md +180 -0
  111. coordinator_node-0.1.0/mkdocs.yml +25 -0
  112. coordinator_node-0.1.0/packs/README.md +26 -0
  113. coordinator_node-0.1.0/pyproject.toml +35 -0
  114. coordinator_node-0.1.0/scripts/verify_e2e.py +153 -0
  115. coordinator_node-0.1.0/tests/test_backfill.py +105 -0
  116. coordinator_node-0.1.0/tests/test_callable_resolver.py +40 -0
  117. coordinator_node-0.1.0/tests/test_checkpoint_worker.py +401 -0
  118. coordinator_node-0.1.0/tests/test_coordinator_core_schema.py +65 -0
  119. coordinator_node-0.1.0/tests/test_coordinator_runtime_data_feeds.py +89 -0
  120. coordinator_node-0.1.0/tests/test_core_entities.py +53 -0
  121. coordinator_node-0.1.0/tests/test_node_template_predict_service.py +191 -0
  122. coordinator_node-0.1.0/tests/test_node_template_report_worker.py +138 -0
  123. coordinator_node-0.1.0/tests/test_node_template_repositories.py +36 -0
  124. coordinator_node-0.1.0/tests/test_node_template_score_service.py +245 -0
  125. coordinator_node-0.1.0/tests/test_prediction_lifecycle.py +470 -0
  126. 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,2 @@
1
+ .venv
2
+ deployment
@@ -0,0 +1,18 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ .idea
13
+
14
+ data/
15
+
16
+ # Local challenge implementations/workspaces
17
+ crunch-implementations/
18
+ *.DS_Store
@@ -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
+ ```