coordinator-node 0.1.2__tar.gz → 0.1.3__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.2 → coordinator_node-0.1.3}/PKG-INFO +1 -1
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/Dockerfile +1 -1
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/docker-compose.yml +5 -5
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/repositories.py +1 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/score.py +8 -1
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/report_worker.py +88 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/pyproject.toml +1 -1
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_checkpoint_worker.py +92 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_node_template_predict_service.py +66 -2
- coordinator_node-0.1.3/tests/test_node_template_repositories.py +86 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/uv.lock +1 -1
- coordinator_node-0.1.2/tests/test_node_template_repositories.py +0 -39
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.dev.env +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.dockerignore +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.gitignore +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.local.env +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.production.env +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/.python-version +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/Dockerfile +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/Makefile +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/SKILL.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/Makefile +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/SKILL.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/SKILL.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/pyproject.toml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/examples/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/examples/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/examples/mean_reversion_tracker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/examples/trend_following_tracker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/examples/volatility_regime_tracker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/schemas/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/scoring.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/tracker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/.local.env +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/.local.env.example +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/.production.env.example +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/Makefile +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/RUNBOOK.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/SKILL.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/config/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/config/callables.env +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/config/scheduled_prediction_configs.json +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/docker-entrypoint.sh +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/models.dev.yml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/orchestrator.dev.yml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/starter-submission/main.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/starter-submission/requirements.txt +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/model-orchestrator-local/config/starter-submission/tracker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/report-ui/config/global-settings.json +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/report-ui/config/leaderboard-columns.json +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/deployment/report-ui/config/metrics-widgets.json +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/extensions/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/plugins/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/pyproject.toml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/runtime_definitions/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/runtime_definitions/contracts.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/scripts/backfill.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/scripts/capture_runtime_logs.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/scripts/check_models.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/scripts/verify_e2e.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/clean-data.sh +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/config/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/config/extensions.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/config/runtime.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/contracts.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/feed_records.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/init_db.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/pg_notify.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/session.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/tables/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/tables/feed.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/tables/models.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/db/tables/pipeline.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/entities/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/entities/feed_record.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/entities/model.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/entities/prediction.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/extensions/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/extensions/callable_resolver.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/extensions/default_callables.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/base.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/contracts.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/providers/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/providers/binance.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/providers/pyth.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/registry.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/schemas/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/schemas/payload_contracts.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/backfill.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/feed_data.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/feed_reader.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/predict.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/realtime_predict.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/__init__.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/checkpoint_worker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/feed_data_worker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/predict_worker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/score_worker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docker-compose.yml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docs/plans/2026-02-10-coordinator-restructure-design.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docs/plans/2026-02-11-contract-based-architecture.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docs/plans/2026-02-11-scoring-snapshots-checkpoints.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docs/plans/2026-02-11-thin-node-cli-implementation-plan.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/docs/plans/2026-02-11-thin-node-cli-onboarding-design.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/mkdocs.yml +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/packs/README.md +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/scripts/verify_e2e.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_backfill.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_callable_resolver.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_coordinator_core_schema.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_coordinator_runtime_data_feeds.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_core_entities.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_node_template_report_worker.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_node_template_score_service.py +0 -0
- {coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_prediction_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coordinator-node
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Runtime engine for Crunch coordinator nodes
|
|
5
5
|
Project-URL: Homepage, https://github.com/crunchdao/coordinator-node-starter
|
|
6
6
|
Project-URL: Repository, https://github.com/crunchdao/coordinator-node-starter
|
|
@@ -8,7 +8,7 @@ WORKDIR /app
|
|
|
8
8
|
|
|
9
9
|
# Coordinator engine (from PyPI)
|
|
10
10
|
# Bump this to force Docker to re-pull the latest package version
|
|
11
|
-
ARG COORDINATOR_NODE_VERSION=0.1.
|
|
11
|
+
ARG COORDINATOR_NODE_VERSION=0.1.3
|
|
12
12
|
RUN pip install --no-cache-dir "coordinator-node>=${COORDINATOR_NODE_VERSION}"
|
|
13
13
|
|
|
14
14
|
# Challenge package
|
|
@@ -62,7 +62,7 @@ services:
|
|
|
62
62
|
FEED_BACKFILL_MINUTES: ${FEED_BACKFILL_MINUTES:-180}
|
|
63
63
|
FEED_RECORD_TTL_DAYS: ${FEED_RECORD_TTL_DAYS:-90}
|
|
64
64
|
FEED_RETENTION_CHECK_SECONDS: ${FEED_RETENTION_CHECK_SECONDS:-3600}
|
|
65
|
-
PYTHONPATH: /app/challenge
|
|
65
|
+
PYTHONPATH: /app:/app/challenge
|
|
66
66
|
volumes:
|
|
67
67
|
- ../challenge:/app/challenge
|
|
68
68
|
depends_on:
|
|
@@ -93,7 +93,7 @@ services:
|
|
|
93
93
|
FEED_SUBJECTS: ${FEED_SUBJECTS:-BTC}
|
|
94
94
|
FEED_KIND: ${FEED_KIND:-tick}
|
|
95
95
|
FEED_GRANULARITY: ${FEED_GRANULARITY:-1s}
|
|
96
|
-
PYTHONPATH: /app/challenge
|
|
96
|
+
PYTHONPATH: /app:/app/challenge
|
|
97
97
|
volumes:
|
|
98
98
|
- ../challenge:/app/challenge
|
|
99
99
|
depends_on:
|
|
@@ -124,7 +124,7 @@ services:
|
|
|
124
124
|
FEED_KIND: ${FEED_KIND:-tick}
|
|
125
125
|
FEED_GRANULARITY: ${FEED_GRANULARITY:-1s}
|
|
126
126
|
SCORING_FUNCTION: ${SCORING_FUNCTION}
|
|
127
|
-
PYTHONPATH: /app/challenge
|
|
127
|
+
PYTHONPATH: /app:/app/challenge
|
|
128
128
|
volumes:
|
|
129
129
|
- ../challenge:/app/challenge
|
|
130
130
|
depends_on:
|
|
@@ -148,7 +148,7 @@ services:
|
|
|
148
148
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-starter}
|
|
149
149
|
POSTGRES_DB: ${POSTGRES_DB:-starter}
|
|
150
150
|
CHECKPOINT_INTERVAL_SECONDS: ${CHECKPOINT_INTERVAL_SECONDS:-604800}
|
|
151
|
-
PYTHONPATH: /app/challenge
|
|
151
|
+
PYTHONPATH: /app:/app/challenge
|
|
152
152
|
volumes:
|
|
153
153
|
- ../challenge:/app/challenge
|
|
154
154
|
depends_on:
|
|
@@ -171,7 +171,7 @@ services:
|
|
|
171
171
|
POSTGRES_USER: ${POSTGRES_USER:-starter}
|
|
172
172
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-starter}
|
|
173
173
|
POSTGRES_DB: ${POSTGRES_DB:-starter}
|
|
174
|
-
PYTHONPATH: /app/challenge
|
|
174
|
+
PYTHONPATH: /app:/app/challenge
|
|
175
175
|
volumes:
|
|
176
176
|
- ../challenge:/app/challenge
|
|
177
177
|
depends_on:
|
|
@@ -168,6 +168,7 @@ class DBPredictionRepository:
|
|
|
168
168
|
existing.meta_jsonb = row.meta_jsonb
|
|
169
169
|
existing.scope_key = row.scope_key
|
|
170
170
|
existing.scope_jsonb = row.scope_jsonb
|
|
171
|
+
existing.resolvable_at = row.resolvable_at
|
|
171
172
|
self._session.commit()
|
|
172
173
|
|
|
173
174
|
def save_all(self, predictions: Iterable[PredictionRecord]) -> None:
|
|
@@ -224,7 +224,7 @@ class ScoreService:
|
|
|
224
224
|
metrics: dict[str, float] = {}
|
|
225
225
|
for window_name, window in aggregation.windows.items():
|
|
226
226
|
cutoff = now - timedelta(hours=window.hours)
|
|
227
|
-
window_snaps = [s for s in model_snapshots if s.period_end >= cutoff]
|
|
227
|
+
window_snaps = [s for s in model_snapshots if self._ensure_utc(s.period_end) >= cutoff]
|
|
228
228
|
if window_snaps:
|
|
229
229
|
vals = [float(s.result_summary.get(aggregation.ranking_key, 0)) for s in window_snaps]
|
|
230
230
|
metrics[window_name] = sum(vals) / len(vals)
|
|
@@ -270,6 +270,13 @@ class ScoreService:
|
|
|
270
270
|
|
|
271
271
|
_rank_leaderboard = _rank
|
|
272
272
|
|
|
273
|
+
@staticmethod
|
|
274
|
+
def _ensure_utc(dt: datetime) -> datetime:
|
|
275
|
+
"""Ensure a datetime is timezone-aware (assume UTC if naive)."""
|
|
276
|
+
if dt.tzinfo is None:
|
|
277
|
+
return dt.replace(tzinfo=timezone.utc)
|
|
278
|
+
return dt
|
|
279
|
+
|
|
273
280
|
def _rollback_repositories(self) -> None:
|
|
274
281
|
for name, repo in [("input", self.input_repository),
|
|
275
282
|
("prediction", self.prediction_repository),
|
|
@@ -667,6 +667,94 @@ def get_checkpoint_emission_cli_format(
|
|
|
667
667
|
}
|
|
668
668
|
|
|
669
669
|
|
|
670
|
+
@app.get("/reports/checkpoints/{checkpoint_id}/prizes")
|
|
671
|
+
def get_checkpoint_prizes(
|
|
672
|
+
checkpoint_id: str,
|
|
673
|
+
checkpoint_repo: Annotated[DBCheckpointRepository, Depends(get_checkpoint_repository)],
|
|
674
|
+
total_prize: Annotated[int, Query(description="Total prize pool to distribute (in token lowest denomination)")] = 0,
|
|
675
|
+
) -> list[dict[str, Any]]:
|
|
676
|
+
"""Return checkpoint emission as Prize[] JSON for the coordinator webapp.
|
|
677
|
+
|
|
678
|
+
The webapp's CreateCheckpoint UI expects:
|
|
679
|
+
[{prizeId, timestamp, model, prize}]
|
|
680
|
+
where `model` is a model ID and `prize` is an absolute token amount.
|
|
681
|
+
|
|
682
|
+
This endpoint converts the node's frac64 percentage-based emission into
|
|
683
|
+
the webapp format by distributing `total_prize` proportionally.
|
|
684
|
+
"""
|
|
685
|
+
checkpoints = checkpoint_repo.find()
|
|
686
|
+
checkpoint = next((c for c in checkpoints if c.id == checkpoint_id), None)
|
|
687
|
+
if checkpoint is None:
|
|
688
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Checkpoint not found")
|
|
689
|
+
if not checkpoint.entries:
|
|
690
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No emission data in checkpoint")
|
|
691
|
+
|
|
692
|
+
emission = checkpoint.entries[0]
|
|
693
|
+
ranking = checkpoint.meta.get("ranking", [])
|
|
694
|
+
frac64_multiplier = 1_000_000_000
|
|
695
|
+
timestamp = int(checkpoint.period_end.timestamp())
|
|
696
|
+
|
|
697
|
+
prizes: list[dict[str, Any]] = []
|
|
698
|
+
for reward in emission.get("cruncher_rewards", []):
|
|
699
|
+
idx = reward["cruncher_index"]
|
|
700
|
+
pct = reward["reward_pct"] / frac64_multiplier
|
|
701
|
+
model_id = ranking[idx]["model_id"] if idx < len(ranking) else str(idx)
|
|
702
|
+
|
|
703
|
+
prize_amount = int(round(total_prize * pct))
|
|
704
|
+
prizes.append({
|
|
705
|
+
"prizeId": f"{checkpoint_id}-{model_id}",
|
|
706
|
+
"timestamp": timestamp,
|
|
707
|
+
"model": model_id,
|
|
708
|
+
"prize": prize_amount,
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
return prizes
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
@app.get("/reports/checkpoints/latest/prizes")
|
|
715
|
+
def get_latest_checkpoint_prizes(
|
|
716
|
+
checkpoint_repo: Annotated[DBCheckpointRepository, Depends(get_checkpoint_repository)],
|
|
717
|
+
total_prize: Annotated[int, Query(description="Total prize pool to distribute (in token lowest denomination)")] = 0,
|
|
718
|
+
) -> dict[str, Any]:
|
|
719
|
+
"""Return the latest checkpoint's prizes in webapp format.
|
|
720
|
+
|
|
721
|
+
Convenience wrapper that finds the latest checkpoint and returns its prizes.
|
|
722
|
+
"""
|
|
723
|
+
checkpoint = checkpoint_repo.get_latest()
|
|
724
|
+
if checkpoint is None:
|
|
725
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No checkpoints found")
|
|
726
|
+
if not checkpoint.entries:
|
|
727
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No emission data in checkpoint")
|
|
728
|
+
|
|
729
|
+
emission = checkpoint.entries[0]
|
|
730
|
+
ranking = checkpoint.meta.get("ranking", [])
|
|
731
|
+
frac64_multiplier = 1_000_000_000
|
|
732
|
+
timestamp = int(checkpoint.period_end.timestamp())
|
|
733
|
+
|
|
734
|
+
prizes: list[dict[str, Any]] = []
|
|
735
|
+
for reward in emission.get("cruncher_rewards", []):
|
|
736
|
+
idx = reward["cruncher_index"]
|
|
737
|
+
pct = reward["reward_pct"] / frac64_multiplier
|
|
738
|
+
model_id = ranking[idx]["model_id"] if idx < len(ranking) else str(idx)
|
|
739
|
+
|
|
740
|
+
prize_amount = int(round(total_prize * pct))
|
|
741
|
+
prizes.append({
|
|
742
|
+
"prizeId": f"{checkpoint.id}-{model_id}",
|
|
743
|
+
"timestamp": timestamp,
|
|
744
|
+
"model": model_id,
|
|
745
|
+
"prize": prize_amount,
|
|
746
|
+
})
|
|
747
|
+
|
|
748
|
+
return {
|
|
749
|
+
"checkpoint_id": checkpoint.id,
|
|
750
|
+
"status": checkpoint.status,
|
|
751
|
+
"period_start": checkpoint.period_start.isoformat(),
|
|
752
|
+
"period_end": checkpoint.period_end.isoformat(),
|
|
753
|
+
"total_prize": total_prize,
|
|
754
|
+
"prizes": prizes,
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
|
|
670
758
|
@app.get("/reports/emissions/latest")
|
|
671
759
|
def get_latest_emission(
|
|
672
760
|
checkpoint_repo: Annotated[DBCheckpointRepository, Depends(get_checkpoint_repository)],
|
|
@@ -397,5 +397,97 @@ class TestEmissionEndpoints(unittest.TestCase):
|
|
|
397
397
|
self.assertEqual(result["emission"]["crunch"], "crunch_abc")
|
|
398
398
|
|
|
399
399
|
|
|
400
|
+
# ── Prizes endpoint tests ──
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class TestPrizesEndpoints(unittest.TestCase):
|
|
404
|
+
def _make_checkpoint(self) -> CheckpointRecord:
|
|
405
|
+
return CheckpointRecord(
|
|
406
|
+
id="CKP_001",
|
|
407
|
+
period_start=now - timedelta(days=7),
|
|
408
|
+
period_end=now,
|
|
409
|
+
status=CheckpointStatus.PENDING,
|
|
410
|
+
entries=[{
|
|
411
|
+
"crunch": "crunch_abc",
|
|
412
|
+
"cruncher_rewards": [
|
|
413
|
+
{"cruncher_index": 0, "reward_pct": 600_000_000},
|
|
414
|
+
{"cruncher_index": 1, "reward_pct": 400_000_000},
|
|
415
|
+
],
|
|
416
|
+
"compute_provider_rewards": [],
|
|
417
|
+
"data_provider_rewards": [],
|
|
418
|
+
}],
|
|
419
|
+
meta={"ranking": [
|
|
420
|
+
{"model_id": "m1", "rank": 1},
|
|
421
|
+
{"model_id": "m2", "rank": 2},
|
|
422
|
+
]},
|
|
423
|
+
created_at=now,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
def test_get_checkpoint_prizes_format(self):
|
|
427
|
+
from coordinator_node.workers.report_worker import get_checkpoint_prizes
|
|
428
|
+
|
|
429
|
+
repo = MemCheckpointRepository([self._make_checkpoint()])
|
|
430
|
+
result = get_checkpoint_prizes("CKP_001", repo, total_prize=1_000_000)
|
|
431
|
+
|
|
432
|
+
self.assertEqual(len(result), 2)
|
|
433
|
+
# First model gets 60%
|
|
434
|
+
self.assertEqual(result[0]["model"], "m1")
|
|
435
|
+
self.assertEqual(result[0]["prize"], 600_000)
|
|
436
|
+
self.assertEqual(result[0]["prizeId"], "CKP_001-m1")
|
|
437
|
+
self.assertIn("timestamp", result[0])
|
|
438
|
+
# Second model gets 40%
|
|
439
|
+
self.assertEqual(result[1]["model"], "m2")
|
|
440
|
+
self.assertEqual(result[1]["prize"], 400_000)
|
|
441
|
+
|
|
442
|
+
def test_get_checkpoint_prizes_zero_total(self):
|
|
443
|
+
from coordinator_node.workers.report_worker import get_checkpoint_prizes
|
|
444
|
+
|
|
445
|
+
repo = MemCheckpointRepository([self._make_checkpoint()])
|
|
446
|
+
result = get_checkpoint_prizes("CKP_001", repo, total_prize=0)
|
|
447
|
+
|
|
448
|
+
self.assertEqual(len(result), 2)
|
|
449
|
+
self.assertEqual(result[0]["prize"], 0)
|
|
450
|
+
self.assertEqual(result[1]["prize"], 0)
|
|
451
|
+
|
|
452
|
+
def test_get_checkpoint_prizes_not_found(self):
|
|
453
|
+
from coordinator_node.workers.report_worker import get_checkpoint_prizes
|
|
454
|
+
from fastapi import HTTPException
|
|
455
|
+
|
|
456
|
+
repo = MemCheckpointRepository()
|
|
457
|
+
with self.assertRaises(HTTPException):
|
|
458
|
+
get_checkpoint_prizes("CKP_NONEXISTENT", repo, total_prize=1000)
|
|
459
|
+
|
|
460
|
+
def test_get_checkpoint_prizes_sums_to_total(self):
|
|
461
|
+
from coordinator_node.workers.report_worker import get_checkpoint_prizes
|
|
462
|
+
|
|
463
|
+
repo = MemCheckpointRepository([self._make_checkpoint()])
|
|
464
|
+
total = 999_999
|
|
465
|
+
result = get_checkpoint_prizes("CKP_001", repo, total_prize=total)
|
|
466
|
+
|
|
467
|
+
actual_sum = sum(p["prize"] for p in result)
|
|
468
|
+
# May differ by ±1 due to rounding, but should be close
|
|
469
|
+
self.assertAlmostEqual(actual_sum, total, delta=len(result))
|
|
470
|
+
|
|
471
|
+
def test_get_latest_checkpoint_prizes(self):
|
|
472
|
+
from coordinator_node.workers.report_worker import get_latest_checkpoint_prizes
|
|
473
|
+
|
|
474
|
+
repo = MemCheckpointRepository([self._make_checkpoint()])
|
|
475
|
+
result = get_latest_checkpoint_prizes(repo, total_prize=1_000_000)
|
|
476
|
+
|
|
477
|
+
self.assertEqual(result["checkpoint_id"], "CKP_001")
|
|
478
|
+
self.assertEqual(result["total_prize"], 1_000_000)
|
|
479
|
+
self.assertEqual(len(result["prizes"]), 2)
|
|
480
|
+
self.assertEqual(result["prizes"][0]["model"], "m1")
|
|
481
|
+
self.assertEqual(result["prizes"][0]["prize"], 600_000)
|
|
482
|
+
|
|
483
|
+
def test_get_latest_checkpoint_prizes_not_found(self):
|
|
484
|
+
from coordinator_node.workers.report_worker import get_latest_checkpoint_prizes
|
|
485
|
+
from fastapi import HTTPException
|
|
486
|
+
|
|
487
|
+
repo = MemCheckpointRepository()
|
|
488
|
+
with self.assertRaises(HTTPException):
|
|
489
|
+
get_latest_checkpoint_prizes(repo, total_prize=1000)
|
|
490
|
+
|
|
491
|
+
|
|
400
492
|
if __name__ == "__main__":
|
|
401
493
|
unittest.main()
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_node_template_predict_service.py
RENAMED
|
@@ -2,7 +2,7 @@ import unittest
|
|
|
2
2
|
from datetime import datetime, timezone
|
|
3
3
|
|
|
4
4
|
from coordinator_node.entities.model import Model
|
|
5
|
-
from coordinator_node.entities.prediction import PredictionRecord
|
|
5
|
+
from coordinator_node.entities.prediction import InputRecord, PredictionRecord
|
|
6
6
|
from coordinator_node.contracts import CrunchContract
|
|
7
7
|
from coordinator_node.services.realtime_predict import RealtimePredictService
|
|
8
8
|
|
|
@@ -111,16 +111,33 @@ class InMemoryPredictionRepository:
|
|
|
111
111
|
]
|
|
112
112
|
|
|
113
113
|
|
|
114
|
+
class InMemoryInputRepository:
|
|
115
|
+
def __init__(self):
|
|
116
|
+
self.records: list[InputRecord] = []
|
|
117
|
+
|
|
118
|
+
def save(self, record: InputRecord):
|
|
119
|
+
for i, r in enumerate(self.records):
|
|
120
|
+
if r.id == record.id:
|
|
121
|
+
self.records[i] = record
|
|
122
|
+
return
|
|
123
|
+
self.records.append(record)
|
|
124
|
+
|
|
125
|
+
def find(self, **kwargs):
|
|
126
|
+
return list(self.records)
|
|
127
|
+
|
|
128
|
+
|
|
114
129
|
class NoConfigPredictionRepository(InMemoryPredictionRepository):
|
|
115
130
|
def fetch_active_configs(self):
|
|
116
131
|
return []
|
|
117
132
|
|
|
118
133
|
|
|
119
|
-
def _make_service(feed_reader=None, prediction_repo=None,
|
|
134
|
+
def _make_service(feed_reader=None, prediction_repo=None, input_repo=None,
|
|
135
|
+
runner=None, contract=None):
|
|
120
136
|
return RealtimePredictService(
|
|
121
137
|
checkpoint_interval_seconds=60,
|
|
122
138
|
feed_reader=feed_reader or FakeFeedReader(),
|
|
123
139
|
contract=contract or CrunchContract(),
|
|
140
|
+
input_repository=input_repo,
|
|
124
141
|
model_repository=InMemoryModelRepository(),
|
|
125
142
|
prediction_repository=prediction_repo or InMemoryPredictionRepository(),
|
|
126
143
|
runner=runner or FakeRunner(),
|
|
@@ -191,5 +208,52 @@ class TestRealtimePredictService(unittest.IsolatedAsyncioTestCase):
|
|
|
191
208
|
self.assertTrue(any("INFERENCE_OUTPUT_VALIDATION_ERROR" in line for line in logs.output))
|
|
192
209
|
|
|
193
210
|
|
|
211
|
+
async def test_run_once_sets_input_scope_with_feed_dimensions(self):
|
|
212
|
+
"""Regression: input scope must include source/subject/kind/granularity
|
|
213
|
+
so the score worker can query matching feed records for ground truth."""
|
|
214
|
+
input_repo = InMemoryInputRepository()
|
|
215
|
+
pred_repo = InMemoryPredictionRepository()
|
|
216
|
+
feed_reader = FakeFeedReader({"symbol": "BTC"})
|
|
217
|
+
feed_reader.source = "binance"
|
|
218
|
+
feed_reader.subject = "BTC"
|
|
219
|
+
feed_reader.kind = "candle"
|
|
220
|
+
feed_reader.granularity = "1m"
|
|
221
|
+
|
|
222
|
+
service = _make_service(
|
|
223
|
+
feed_reader=feed_reader,
|
|
224
|
+
prediction_repo=pred_repo,
|
|
225
|
+
input_repo=input_repo,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
await service.run_once(raw_input={"symbol": "BTC"}, now=datetime.now(timezone.utc))
|
|
229
|
+
|
|
230
|
+
self.assertEqual(len(input_repo.records), 1)
|
|
231
|
+
inp = input_repo.records[0]
|
|
232
|
+
# Feed dimensions must be in scope for score worker to query feed records
|
|
233
|
+
self.assertEqual(inp.scope.get("source"), "binance")
|
|
234
|
+
self.assertEqual(inp.scope.get("kind"), "candle")
|
|
235
|
+
self.assertEqual(inp.scope.get("granularity"), "1m")
|
|
236
|
+
# subject comes from config scope_template, which may override feed_reader
|
|
237
|
+
self.assertIn("subject", inp.scope)
|
|
238
|
+
|
|
239
|
+
async def test_run_once_sets_input_resolvable_at(self):
|
|
240
|
+
"""Regression: input resolvable_at must be set so the score worker
|
|
241
|
+
can find inputs that are ready for ground truth resolution."""
|
|
242
|
+
input_repo = InMemoryInputRepository()
|
|
243
|
+
pred_repo = InMemoryPredictionRepository()
|
|
244
|
+
service = _make_service(
|
|
245
|
+
prediction_repo=pred_repo,
|
|
246
|
+
input_repo=input_repo,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
now = datetime.now(timezone.utc)
|
|
250
|
+
await service.run_once(raw_input={"symbol": "BTC"}, now=now)
|
|
251
|
+
|
|
252
|
+
self.assertEqual(len(input_repo.records), 1)
|
|
253
|
+
inp = input_repo.records[0]
|
|
254
|
+
self.assertIsNotNone(inp.resolvable_at)
|
|
255
|
+
self.assertGreater(inp.resolvable_at, now)
|
|
256
|
+
|
|
257
|
+
|
|
194
258
|
if __name__ == "__main__":
|
|
195
259
|
unittest.main()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
from coordinator_node.db.repositories import (
|
|
5
|
+
DBInputRepository,
|
|
6
|
+
DBLeaderboardRepository,
|
|
7
|
+
DBModelRepository,
|
|
8
|
+
DBPredictionRepository,
|
|
9
|
+
DBScoreRepository,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestRepositoryAPIs(unittest.TestCase):
|
|
14
|
+
def test_model_repository_has_required_methods(self):
|
|
15
|
+
self.assertTrue(callable(getattr(DBModelRepository, "fetch_all", None)))
|
|
16
|
+
self.assertTrue(callable(getattr(DBModelRepository, "save", None)))
|
|
17
|
+
|
|
18
|
+
def test_input_repository_has_required_methods(self):
|
|
19
|
+
self.assertTrue(callable(getattr(DBInputRepository, "save", None)))
|
|
20
|
+
self.assertTrue(callable(getattr(DBInputRepository, "find", None)))
|
|
21
|
+
|
|
22
|
+
def test_prediction_repository_has_required_methods(self):
|
|
23
|
+
self.assertTrue(callable(getattr(DBPredictionRepository, "save", None)))
|
|
24
|
+
self.assertTrue(callable(getattr(DBPredictionRepository, "save_all", None)))
|
|
25
|
+
self.assertTrue(callable(getattr(DBPredictionRepository, "find", None)))
|
|
26
|
+
|
|
27
|
+
def test_score_repository_has_required_methods(self):
|
|
28
|
+
self.assertTrue(callable(getattr(DBScoreRepository, "save", None)))
|
|
29
|
+
self.assertTrue(callable(getattr(DBScoreRepository, "find", None)))
|
|
30
|
+
|
|
31
|
+
def test_prediction_repository_has_query_scores_method(self):
|
|
32
|
+
self.assertTrue(callable(getattr(DBPredictionRepository, "query_scores", None)))
|
|
33
|
+
|
|
34
|
+
def test_leaderboard_repository_has_required_methods(self):
|
|
35
|
+
self.assertTrue(callable(getattr(DBLeaderboardRepository, "save", None)))
|
|
36
|
+
self.assertTrue(callable(getattr(DBLeaderboardRepository, "get_latest", None)))
|
|
37
|
+
|
|
38
|
+
def test_input_repository_save_updates_scope_and_resolvable_at(self):
|
|
39
|
+
"""Regression: DBInputRepository.save() must update scope_jsonb and
|
|
40
|
+
resolvable_at on existing records, not just status/actuals/meta."""
|
|
41
|
+
source = inspect.getsource(DBInputRepository.save)
|
|
42
|
+
self.assertIn("scope_jsonb", source,
|
|
43
|
+
"save() must update scope_jsonb on existing records")
|
|
44
|
+
self.assertIn("resolvable_at", source,
|
|
45
|
+
"save() must update resolvable_at on existing records")
|
|
46
|
+
|
|
47
|
+
def test_prediction_repository_save_updates_resolvable_at(self):
|
|
48
|
+
"""Regression: DBPredictionRepository.save() must update resolvable_at
|
|
49
|
+
on existing records."""
|
|
50
|
+
source = inspect.getsource(DBPredictionRepository.save)
|
|
51
|
+
self.assertIn("existing.resolvable_at", source,
|
|
52
|
+
"save() must update resolvable_at on existing records")
|
|
53
|
+
|
|
54
|
+
def test_all_repository_save_methods_update_all_constructor_fields(self):
|
|
55
|
+
"""Regression: every save() method must update all fields it constructs,
|
|
56
|
+
except the primary key (id). Catches field omission bugs like the
|
|
57
|
+
scope_jsonb/resolvable_at issue."""
|
|
58
|
+
import re
|
|
59
|
+
from coordinator_node.db.repositories import (
|
|
60
|
+
DBCheckpointRepository, DBSnapshotRepository,
|
|
61
|
+
)
|
|
62
|
+
repos = [
|
|
63
|
+
("DBModelRepository", DBModelRepository),
|
|
64
|
+
("DBInputRepository", DBInputRepository),
|
|
65
|
+
("DBPredictionRepository", DBPredictionRepository),
|
|
66
|
+
("DBScoreRepository", DBScoreRepository),
|
|
67
|
+
("DBSnapshotRepository", DBSnapshotRepository),
|
|
68
|
+
("DBCheckpointRepository", DBCheckpointRepository),
|
|
69
|
+
]
|
|
70
|
+
for name, cls in repos:
|
|
71
|
+
source = inspect.getsource(cls.save)
|
|
72
|
+
# Fields assigned via row.X in constructor
|
|
73
|
+
row_fields = set(re.findall(r'(\w+)=row\.(\w+)', source))
|
|
74
|
+
constructor_fields = {f[0] for f in row_fields if f[0] != 'id'}
|
|
75
|
+
# Fields updated via existing.X = row.X
|
|
76
|
+
existing_fields = set(re.findall(r'existing\.(\w+)\s*=\s*row\.(\w+)', source))
|
|
77
|
+
update_fields = {f[0] for f in existing_fields}
|
|
78
|
+
|
|
79
|
+
missing = constructor_fields - update_fields
|
|
80
|
+
self.assertEqual(missing, set(),
|
|
81
|
+
f"{name}.save() creates fields {sorted(missing)} "
|
|
82
|
+
f"but doesn't update them on existing records")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
unittest.main()
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from coordinator_node.db.repositories import (
|
|
4
|
-
DBInputRepository,
|
|
5
|
-
DBLeaderboardRepository,
|
|
6
|
-
DBModelRepository,
|
|
7
|
-
DBPredictionRepository,
|
|
8
|
-
DBScoreRepository,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class TestRepositoryAPIs(unittest.TestCase):
|
|
13
|
-
def test_model_repository_has_required_methods(self):
|
|
14
|
-
self.assertTrue(callable(getattr(DBModelRepository, "fetch_all", None)))
|
|
15
|
-
self.assertTrue(callable(getattr(DBModelRepository, "save", None)))
|
|
16
|
-
|
|
17
|
-
def test_input_repository_has_required_methods(self):
|
|
18
|
-
self.assertTrue(callable(getattr(DBInputRepository, "save", None)))
|
|
19
|
-
self.assertTrue(callable(getattr(DBInputRepository, "find", None)))
|
|
20
|
-
|
|
21
|
-
def test_prediction_repository_has_required_methods(self):
|
|
22
|
-
self.assertTrue(callable(getattr(DBPredictionRepository, "save", None)))
|
|
23
|
-
self.assertTrue(callable(getattr(DBPredictionRepository, "save_all", None)))
|
|
24
|
-
self.assertTrue(callable(getattr(DBPredictionRepository, "find", None)))
|
|
25
|
-
|
|
26
|
-
def test_score_repository_has_required_methods(self):
|
|
27
|
-
self.assertTrue(callable(getattr(DBScoreRepository, "save", None)))
|
|
28
|
-
self.assertTrue(callable(getattr(DBScoreRepository, "find", None)))
|
|
29
|
-
|
|
30
|
-
def test_prediction_repository_has_query_scores_method(self):
|
|
31
|
-
self.assertTrue(callable(getattr(DBPredictionRepository, "query_scores", None)))
|
|
32
|
-
|
|
33
|
-
def test_leaderboard_repository_has_required_methods(self):
|
|
34
|
-
self.assertTrue(callable(getattr(DBLeaderboardRepository, "save", None)))
|
|
35
|
-
self.assertTrue(callable(getattr(DBLeaderboardRepository, "get_latest", None)))
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if __name__ == "__main__":
|
|
39
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/schemas/README.md
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/scoring.py
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/challenge/starter_challenge/tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/config/scheduled_prediction_configs.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/base/node/runtime_definitions/contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/extensions/callable_resolver.py
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/extensions/default_callables.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/providers/__init__.py
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/feeds/providers/binance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/schemas/payload_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/services/realtime_predict.py
RENAMED
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/checkpoint_worker.py
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/feed_data_worker.py
RENAMED
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/coordinator_node/workers/predict_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coordinator_node-0.1.2 → coordinator_node-0.1.3}/tests/test_coordinator_runtime_data_feeds.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|