Skip to content

Unified bitemporal energy-data platform (S1)#22

Merged
oldhero5 merged 76 commits into
mainfrom
feat/unified-platform-s1
Jun 18, 2026
Merged

Unified bitemporal energy-data platform (S1)#22
oldhero5 merged 76 commits into
mainfrom
feat/unified-platform-s1

Conversation

@oldhero5

Copy link
Copy Markdown
Owner

Rebuilds Energex from a single-file DuckDB/yfinance library into a self-hosted, always-on bitemporal energy-data platform (point-in-time-correct store of record), shipped as S1 of a decomposed program (S2 serving · S3 agent · S4 frontend reserved).

Architecture

  • Hexagonal core (energex.core, zero framework imports, CI-enforced): connectors, ArcticDB-on-MinIO storage, pandera quality gate, symbology, schemas, config.
  • Bitemporal storage: per-symbol integer version index for vintage addressing (not datetime-as_of), crash-safe atomic commit, three revision modes (degenerate / merge / replace), and a vintage_reconstructed honesty flag (EIA/ERCOT revise inline, so true point-in-time only accrues going forward).
  • Dagster orchestration (energex.orchestration, the only Dagster importer): assets, asset-checks, partitions, 4 always-on schedules, reconcile/GC; Postgres-backed instance.
  • Live connectors → ArcticDB libraries: EIA v2 fundamentals (fundamentals.eia), NOAA nClimDiv weather (weather), FRED benchmark spot prices (prices.spot); yfinance intraday futures dev-only (prices.intraday).
  • S2 read-API seam (energex.service.readapi): read-only FastAPI with as_of first-class for the (separate, private) frontend; frontend/ is gitignored + wired in compose.
  • Always-on stack: docker compose --profile full up -d → MinIO + Dagster (webserver/daemon/Postgres) + Neo4j + the read API; verified running with real data ingesting on schedule.

Quality & security

  • Crash-safe bitemporal CI gate suite + connector/quality/storage gates; 185 tests green.
  • Security review (URI-credential redaction fix); full git-history secret scan clean; strengthened pre-commit hooks (gitleaks, detect-private-key).
  • Removed the superseded legacy DuckDB/APScheduler serving stack; pruned internal design artifacts.

Project

  • Relicensed MIT → PolyForm Noncommercial 1.0.0 (source-available) + CITATION.cff; version 0.4.0.
  • Full Docusaurus documentation site (website/): overview, architecture, quickstart, connectors, storage/point-in-time, orchestration, deployment, operations, testing, roadmap, frontend integration.

oldhero5 added 30 commits June 16, 2026 05:58
…ram)

World-class rebuild design, adversarially stress-tested:
- hexagonal core (zero framework imports) + Dagster/FastAPI/LangGraph drivers
- bitemporal ArcticDB-on-MinIO store of record with per-symbol version-index
  vintage addressing (not datetime-as_of), crash-safe atomic commit protocol,
  and a vintage_reconstructed honesty flag for inline-revised sources
- three revision modes (degenerate/merge/replace); single _to_polars adapter
- ERCOT Public REST (not Data Miner 2), monthly nClimDiv weather
- futures migrated off the DuckDB/APScheduler island onto Dagster+ArcticDB
- always-on docker-compose (Postgres instance, Neo4j, MinIO) on the Mac Studio host
Bite-sized TDD tasks (34 tasks / 199 steps) for the unified data platform foundation:
PRE-S1 infra/deps/CI, Phase 0 discovery spikes (EIA freeze, MinIO smoke, vintage
addressing experiment), Phase 1 scaffold + framework-boundary test, Phase 2 crash-safe
bitemporal storage core with 7 gate tests, Phase 3 pandera quality gate. Chrome
verification at the MinIO console and Dagster UI milestones.
oldhero5 added 28 commits June 18, 2026 05:53
…m, NOAA, FRED)

Add ScheduleDefinitions for the working data assets, each targeting a
partitioned asset job and materializing the most recent partition per tick:
- eia_gas_storage      Thu 10:35 ET     (35 10 * * 4)
- eia_petroleum_status Wed 10:35 ET     (35 10 * * 3)
- noaa_degree_days     monthly day 6    (0 12 6 * *)
- fred_spot_prices     weekday 09:30 ET (30 9 * * 1-5)
All set execution_timezone=America/New_York. intraday_futures_bars stays
manual (yfinance blocked). dagster definitions validate passes.
…inIO wiring

- Dockerfile: parametrize installed extras via EXTRAS build arg; create
  /opt/dagster/home owned by nonroot so the named volume inits writable.
- compose: dagster-webserver/daemon now build a dedicated amd64 image
  (energex:dagster) with orchestration+storage+quality+graph extras
  (arcticdb ships no linux/arm64 wheel -> run under emulation). Pass
  MINIO_ENDPOINT=minio:9000 (in-network), scoped ArcticDB service-account
  creds, NEO4J_* and the .env connector keys (EIA/FRED). Daemon loads the
  workspace explicitly via -w.
- workspace.yaml: working_directory -> /app (the image WORKDIR; package is
  installed in the venv, not /opt/dagster/app).
The slim runtime image has no curl, so the curl-based /server_info probe
always failed and the (functional) webserver reported unhealthy. Switch to
the same python urllib probe the energex service uses.
…-on)

Set default_status=RUNNING so the daemon auto-starts the EIA/NOAA/FRED
schedules on an always-on deployment instead of leaving them STOPPED.
Switch from MIT to the PolyForm Noncommercial License 1.0.0 so noncommercial
use (personal/research/education/nonprofit/government) stays free while
commercial use requires a separate paid license, reserving a future
commercial offering.

- LICENSE: verbatim PolyForm Noncommercial 1.0.0 + Required Notice copyright,
  commercial-licensing contact, and a note that prior MIT releases stay MIT.
- CITATION.cff: attribution metadata so users can cite the project.
- README: source-available license section (not OSI 'open source').
- pyproject: license id + 'Free for non-commercial use' classifier.

Note: this binds this and future releases; MIT grants already made are
irrevocable for previously published versions.
…ed docstring

ArcticDB 6.18.1's S3 backend requires creds embedded in the connection URI (the AWS env
credential chain returns 403 against MinIO, verified). Keep EnvVar-sourced creds but:
correct the docstring (it falsely claimed secrets never live in URI literals), and wrap
Arctic() so a connection failure raises a redacted StorageError (endpoint/bucket +
exception type only) -- preventing the cred-bearing URI from leaking via a traceback.
Resolves the sole confidence>=8 finding from the branch security review.
…case-conflict

Strengthen the local secret/safety gates alongside the existing gitleaks hook.
Cross-device (laptop + phone) frontend design brief for interacting with
Energex data, inspired by the Orano Innovations immersive experience
(Immersive Garden). Captures the open-core boundary: the app ships from a
separate private repo and consumes only the S2 read API (as_of first-class);
no frontend code lands in this repo. Covers the cinematic-shell /
instrument-grade-core split, design system, responsive PWA strategy, the
as_of time-travel headline interaction, the API contract seam, tech stack,
phasing, and risks.
Remove the superseded ASSESSMENT.md audit, the internal docs/superpowers/ design artifacts
(preserved in git history; architecture moves to the docs site), the original
energex-ingestion-spec.md, and the phase-0 discovery spike scripts. Rewrite every dangling
ASSESSMENT R## reference in code comments/docstrings/error messages to be self-contained,
and drop the now-moot ASSESSMENT.md entries from .dockerignore and the CI mypy advisory.
- schemas: _business_days_between now localizes tz-naive timestamps to UTC
  before converting, instead of crashing on tz-naive freshness input.
- orchestration/checks: derive as_of from the committed data (max read-back
  as_of) so the read-back quality gate uses the same knowledge time the asset
  wrote, avoiding false freshness failures.
- core/storage: _to_polars guards tz_localize on Datetime/valid_time, only
  localizing when the column is tz-naive.
- ci: connector-gate now also runs the EIA, weather, and readapi tests
  (adds the service extra for the readapi TestClient).
- pyproject: add Python 3.11/3.12/3.13 classifiers (matches requires-python).
- config/exceptions shims: replace dated "122 pre-S1 tests" wording with an
  evergreen backward-compatible-imports note.
- docs/testing: give test_api_contract its own "Public API contract" row
  instead of misclassifying it as a connector test.
- core/exceptions: QualityGateError.failures typed as pd.DataFrame.
- connectors/weather: explicit empty-frame dtypes in _parse_file.
- data_fetcher: use datetime.timezone.utc instead of pytz.UTC.
The platform is now Dagster ingestion + the S2 readapi serving seam, so the old
serving/CLI stack is dead. Removed (no retained code imports them):

- src/energex/service/app.py        (legacy DuckDB FastAPI app)
- src/energex/service/scheduler.py  (in-process APScheduler)
- src/energex/service/pipeline.py   (DuckDB ingestion pipeline)
- src/energex/main.py               (CLI entry point)
- tests/test_service.py, tests/test_main.py (only exercised the above)

Kept src/energex/service/readapi.py (the S2 seam) and refreshed the service
package + readapi docstrings to match.

- docker-compose.yml: dropped the legacy `energex` service and its now-orphaned
  `energex-data` volume; the `api` (readapi) service is the serving layer.
- Dockerfile: default CMD/EXTRAS now target readapi (service+storage) instead of
  the removed app module.
- core/exceptions.py: removed the dead VintageImmutableError (never raised) and
  its assertion in test_core_exceptions.

database.py / data_fetcher.py / sources/* / analysis/* / visualization/* are
intentionally retained (still imported by the public package surface and tests).
…erpreter

Fix two CI-only failures (local 3.12 + --all-extras masked them):
- conftest.py guards its top-level 'import arcticdb' so jobs without the storage extra
  (the pandera quality gate) can still collect their non-storage tests.
- test_dagster_definitions_validate_cli invokes dagster via sys.executable -m dagster
  instead of 'uv run dagster', which re-resolved to a fresh default env (no extras) and
  failed under the 3.11 matrix.
@oldhero5 oldhero5 merged commit 7772115 into main Jun 18, 2026
9 checks passed
@oldhero5 oldhero5 deleted the feat/unified-platform-s1 branch June 18, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant