Containerized environment of the benchmark pipelines across development and production scenarios.
- Docker with Compose plugin
- Google Cloud Platform credentials
interface: Runs the Dagster Webserver on port 3000 and mounts the requested workspace (localorcloud).daemon: Enables the Dagster daemon (sensors, schedules) and is only part of thedevelopmentprofile.lock: Utility service that refreshesrequirements.lock(not required to run the app).
Docker Compose automatically loads environment variables from an .env file in the project root next to compose.yaml.
For production-like tests maintain a dedicated .env.production file with the required connection settings.
# .env.production
WORKSPACE=cloud
GRPC_HOST=<your-grpc-endpoint>
GRPC_PORT=443
DATABASE_HOST=<postgres-host>
DATABASE_PASSWORD=<postgres-password>Keep secret files out of version control via .gitignore.
Start the full stack with the development profile.
docker compose --profile development up --buildOpen the Dagster UI at http://localhost:3000. The local workspace file mounts automatically so no extra environment variables are required.
Inspect persistent logs and artifacts under .dagster/local/* on the host.
Stop the stack with docker compose down or by pressing Ctrl+C in the compose session.
Unit tests run in GitHub Actions for pull requests targeting main and for pushes to main.
The workflow builds the existing pipelines image, installs the development extras inside the test container, and executes the existing unit tests without requiring .env, cloud credentials, or auxiliary services.
Use the same container path locally when you need to reproduce the CI run.
docker build --target pipelines -t benchmark-unit-tests .
docker run --rm \
--user 0:0 \
-e SKIP_DEFAULT_LOGGING_SETUP=1 \
-v "$(pwd)/src:/usr/local/src/benchmark" \
-v "$(pwd)/pyproject.toml:/usr/local/src/pyproject.toml:ro" \
-w /usr/local/src \
benchmark-unit-tests \
bash -lc 'uv pip install --system ".[development]" && python -m pytest -q benchmark'Create or update .env.production with the cloud Dagster GRPC endpoint and Postgres credentials described above.
Launch only the webserver so port 3000 exposes the UI while .dagster/cloud/workspace.yaml targets the remote GRPC server and .dagster/cloud/dagster.yaml connects to Postgres-backed storage.
docker compose --profile production --env-file .env.production up --build interfaceShut the service down with docker compose stop interface or remove containers entirely using docker compose down.
src/definitions/— Dagster orchestration layer (assets, jobs, sensors, partitions)src/scope/— Repository selection, GitHub ingestion, and cohort filteringsrc/attribution/— Bug-inducing commit attribution (knowledge graphs, LLM agents, tracing)src/evaluation/— Annotation projection for result validation.dagster/— Dagster runtime configuration, workspace files, and custom infrastructure components.cloud/— Cloud infrastructure, Terraform stacks, and secret management.jupyter/— Helper package for loading Parquet assets from GCS in notebooks.argilla/— Annotation tooling and Argilla integration
Assets follow a three-part naming scheme:
- Phase — methodological step (e.g.,
scope,extraction,backtracing,evaluation) - Entity — domain object in the singular (e.g.,
repository,change,issue) - Outcome — what the table contains after the stage, as a noun
Resulting format:
<phase>_<entity>_<outcome>
The outcome suffix describes the table content rather than a fixed maturity stage. A phase can have arbitrarily many outcome stages, ordered by data flow. Each outcome is a noun that names what the asset materializes.
Due to a current Dagster limitation, the active branch is prepended as the first path segment of the asset key at registration time (e.g. main/scope_repository_event). The convention above describes the branchless logical name; the branch prefix is a temporary workaround.
Assets are projected to GCS as versioned Parquet files.
The IO layer resolves the current run’s location and version tags and writes assets at:
gs://<bucket>/assets/<asset>/version=<version>/location=<location>/partition=<partition>/data.parquet
<asset>is derived from the logical asset name by replacing underscores with hyphens.<location>encodes the active branch or experiment.<partition>is the asset’s partition key (ordefaultif unpartitioned).
On load, a branch-aware cache is applied:
- Determine the active
location(current branch). - Try to read the projected table for the current location.
- If the branch has no cached projection, load trunk if it differs.
- If no cached projection exists, compute and write a new one.
Assets can be forced to recompute by passing a configuration with compute=force. In that case the cache is ignored and the asset function is always executed before writing a fresh projection.