Run a compute job end to end
Table of Contents
This page documents a runbook — a named, repeatable composition of recipes and skills for a complete multi-step procedure. Each step references a recipe or skill by id-link.
1. Goal
Prove the compute grid end to end on one machine: provision an environment
that has the ORE engine binaries in it, submit the vendored TA002_IR_Swap
sample job, and check that the numbers the engine produced match the Academy
example's ExpectedOutput.
This is the acceptance test for ores.compute. Compute job lifecycle describes what each stage does; this runbook is the sequence that runs it.
2. Preconditions
- The tree is built:
./compass.sh buildexits 0, sobuild/output/$(ORES_PRESET)/publish/binholds the shell, the compute service, the wrapper and the HTTP server. ./compass.sh env configurehas run for the current preset, so.envis at the required format version. Every command below reads its ports and credentials from it.- PostgreSQL and NATS are reachable.
compass services startbrings up NATS and every unit. - The ORE engine package is vendored:
external/ore/packages/holdsore-<version>-x64-linux.tar.gz. The build'svendor_compute_packagestarget copies it intopublish/vendor-packages/, and that copy is whatcompute publish-packageuploads. Seeexternal/ore/packages/README.mdandexternal/ore/packages/methodology.txtfor how a package is built and self-tested. - The sample job input is vendored:
external/ore/packages/TA002_IR_Swap.tar.gz, with its reference output atexternal/ore/examples/Academy/TA002_IR_Swap/ExpectedOutput/. - The machine's platform triplet is
x64-linux, which is the triplet both vendored packages are built for. The wrapper subscribes on its own triplet, so a job published for another platform is never picked up.
3. Steps
In execution order:
Recreate the database and start the fleet. The grid's tables and the notify triggers must come from the current models, so start from a recreated database:
./compass.sh db recreate -y -k ./compass.sh services start iam ./compass.sh services start http.server ./compass.sh services start compute ./compass.sh services start compute.wrapper
The HTTP server is the storage end: the wrapper downloads the engine package, the job input and uploads the output archive over it. Without it every job fails at the first download.
Bootstrap an operator. A recreated database is in bootstrap mode, so no account can log in until the first admin and a tenant exist:
connect $ORES_NATS_URL bootstrap create-initial-admin super_admin@localhost <password> admin@ores.local bootstrap provision-tenant evaluation acme_corporation Acme_Corporation \ acme_corporation "Acme Corporation development tenant" \ tenant_admin@acme_corporation <password> admin@acme.localThe wrappers run in the system tenant and the seed's app version is owned by it, so the batch is submitted as
super_admin@localhost, which resolves to the system tenant.Provision the engine package. This is the step that puts the ORE binaries in the system. Registration and bytes are separate: the seed
compute_ore_app_seed.sqlregisters the app, the app versions and thex64-linuxplatform row, andcompute publish-packageuploads the tarball to storage and verifies its SHA256 server-side.compute publish-package ORE 1.8.17.0 x64-linux \ --wrapper-version 1.0.0 \ --file external/ore/packages/ore-1.8.17.0-x64-linux.tar.gz \ --http-base-url http://localhost:$ORES_HTTP_PORTCheck the provision before going further. The upload prints the SHA256 it computed, and that value must equal both the tarball's own and the one the seed registered:
sha256sum external/ore/packages/ore-1.8.17.0-x64-linux.tar.gz ls -l build/output/$ORES_PRESET/publish/storage/compute/packages/ORE/1.8.17.0/
select av.id, av.engine_version, avp.package_uri, avp.sha256 from ores_compute_app_versions_tbl av join ores_compute_app_version_platforms_tbl avp on avp.app_version_id = av.id join ores_compute_apps_tbl a on a.id = av.app_id where a.name = 'ORE' and av.valid_to > now() and avp.valid_to > now();
A version whose platform row is missing stores the workunits and publishes no assignment, so the jobs sit
Unsent. The dispatcher logs a warning that names the app version and the workunit, which is where to look when a batch never leavesUnsent. Note theidof the1.8.17.0row: the dispatch needs it.Confirm the grid is online. The wrappers register themselves on their first heartbeat:
select count(*) as hosts, count(*) filter (where last_rpc_time > now() - interval '5 minutes') as online from ores_compute_hosts_tbl where valid_to > now();hosts = onlineis the arithmetic that matters: a host outside the five-minute window is not in the grid, and--smokeasserts every online host was exercised.Create the batch and dispatch the sample job. A batch is a container with an operator-chosen reference; dispatch is what stores the workunits, creates one result per job and publishes one assignment per result. The generated entity command creates the batch:
batches add e2e-ir-swap open system.new_record "end to end run" compute dispatch-batch e2e-ir-swap 15 <app_version_id> \ external/ore/packages/TA002_IR_Swap.tar.gzEvery workunit of the batch shares the one input bundle, which is why the workunit's key is its id and not its
input_uri: a key on the input would allow exactly one job per batch.Watch the batch drain.
grid-stats --watch --smokepolls until every workunit has a canonical result, then asserts every result has outcome Success and every host that was online at the drain edge was exercised. It exits non-zero if either assertion fails, so a broken grid shows up here rather than in a downloaded archive nobody compared:compute grid-stats --watch e2e-ir-swap --smoke
Download one job's output. Each finished result has an archive in storage, holding the
Output/directory the engine wrote:results list compute download-output <result_id> build/e2e/out
Compare the output against the Academy example. The reference files are in the vendored example, and
compare_csv.pyis the tolerant comparator the package pipeline already uses: it matches shared columns within a relative tolerance, and reports columns the build added or removed rather than failing on them.for f in curves.csv flows.csv npv.csv; do python3 external/ore/tools/compare_csv.py \ build/e2e/out/$f \ external/ore/examples/Academy/TA002_IR_Swap/ExpectedOutput/$f doneExit 0 on all three is the numerical pass. New columns are reported for review and do not fail the comparison; a changed value or a different row count does.
4. Postconditions
- The ORE engine package is in storage under
compute/packages/ORE/<version>/<version>-x64-linux.tar.gz, with the SHA256 the app version's platform row states. - The batch's external reference is
closed, every workunit carries a canonical result, and every result isserver_state5 withoutcome1. - The downloaded output's
curves.csv,flows.csvandnpv.csvmatch the Academy example'sExpectedOutputwithinrtol1e-6 on every shared column.
5. Observed result
The run on 2026-09-26 produced:
| File | Rows | Shared columns | Result |
|---|---|---|---|
curves.csv |
240 | 4 | every value matched |
flows.csv |
60 | 25 | matched, 4 new columns reported |
npv.csv |
1 | 13 | every value matched |
Fifteen jobs, fifteen successes, one closed batch, five nodes exercised. The
four new flows.csv columns (EffectiveFloorVolatility,
EffectiveCapVolatility, Amount(Base), DiscountFactor(Base)) are engine
schema additions the reference predates; the package's own
.diff-report.txt carries the same note, so it is a reviewed difference and
not a regression.
6. What breaks the run, and what it looks like
- An unpublished package. The upload is the only step that puts bytes in
storage. Registration alone leaves every job
Unsentand the service log silent. - A host outside the online window.
--smokefails its host assertion. A wrapper that has not heartbeated for five minutes is not in the grid. - A mistyped platform triplet. The wrapper subscribes on its own triplet and the dispatcher publishes on the platform row's; a mismatch means the assignment is published and consumed by nobody.
- A stale database. The notify triggers are generated, so a model change needs a recreate. A trigger and the C++ that parses it disagreeing is silent: the service logs a deserialize failure and no job is ever dispatched.
7. See also
- Compute job lifecycle — the stages this runbook runs.
- How do I smoke test the compute grid from the shell? — the drain watch in one script.
- Runbooks catalogue — all runbooks.