Running Jobs
Submit generation jobs, monitor progress, download results, and manage the job lifecycle.
Job Lifecycle
Every generation job progresses through these states:
created -> queued -> running -> succeeded | failed | canceled- Credits for an ordinary job are deducted on
succeeded. A live OT streaming session is quoted and reserved at submission, then reconciled when the session ends - A hash-sealed evidence bundle is written to storage on success; tenant-signed notarization is additionally recorded once your workspace has an evidence signing key
- A provenance seal is committed to the seal registry on success
Creating a Job
from radmah_sdk import RadMahClient
client = RadMahClient(api_key="sl_live_...")
# Synthesize rows from an uploaded dataset
job = client.jobs.create(
kind="synthesize",
dataset_id="...",
rows=100_000,
)
# Wait for completion
job.wait()
print(f"Status: {job.status}")
print(f"Job ID: {job.id}")ℹPrompt-to-data uses the Fabricate preview workflow
Generating tabular data from a natural-language description is not a generic job kind. It runs through the reviewed Fabricate workflow — create_fabricate_preview(), optional refine_fabricate_preview(), then approve_fabricate_preview() — which enqueues the final generation job only after you approve the previewed contract. See the Fabricate guide.
Job Kinds
The platform automatically selects the appropriate generation pipeline for each job kind. Prompt-to-tabular Fabricate is not a generic job kind — it always runs through the reviewed preview workflow described above.
| Kind | Description |
|---|---|
| synthesize | Trained generative model synthesis from uploaded data |
| simulate | Physics-based SCADA/ICS simulation |
| analyze | Column profiling and schema inference on uploaded data |
| train | Train a generative model on uploaded data |
| fit | Compute summary statistics for a seal |
| verify | Verify artifact integrity |
| scenario_fabricate | LLM-authored SCADA/ICS scenario packs |
| lift | Transform raw data into typed WorldState |
Monitoring Jobs
# Check status
job = client.jobs.get(job_id="...")
print(job.status) # "running", "succeeded", etc.
# List recent jobs
jobs = client.jobs.list(limit=10)
for j in jobs:
print(f"{j.id}: {j.status}")
# Wait with timeout
job.wait(timeout=300.0) # raises TimeoutError after 5 minDownloading Results
# As a pandas DataFrame
df = job.to_dataframe()
# List all artifacts for a job
artifacts = client.list_job_artifacts(job.id)
for a in artifacts:
print(f"{a.artifact_type}: {a.sha256}")
# Download a specific artifact's content
content = client.download_artifact(job.id, artifacts[0].id)
with open("output.csv", "w") as fh:
fh.write(content)Canceling and Rerunning
# Cancel a running job
client.jobs.cancel(job_id="...")
# Rerun a completed job (same sealed contract, same seed = identical output)
rerun = client.jobs.rerun(job_id=job.id)
rerun.wait()Queue Routing
Jobs are automatically routed to the appropriate Celery queue based on job kind and plan tier:
| Queue | Purpose |
|---|---|
| radmah-default | Standard synthesize, analyze, and verify jobs |
| radmah-gpu | GPU-accelerated training jobs |
| radmah-free | Free-tier jobs (lower priority) |
| radmah-interactive | Chat-triggered quick jobs (low latency) |
Credit Estimation
Before submitting a job, you can estimate the credit cost:
# POST /v1/client/estimate takes the contract dict, not a bare row count
estimate = client.estimate_job(contract, seed=42)
print(estimate["credits_required"]) # total credits at submission
print(estimate["credits_generation"]) # row-based generation cost
print(estimate["requested_records"]) # row count the estimate usedℹCredit Rate
Generation credit rate: 1 credit = 1,000,000 rows for Fabricate, Synthesis, and CCTP; 1 credit = 500,000 rows for Virtual SCADA and ICS Security. Streaming SCADA/ICS sessions add a duration surcharge. The platform always shows the estimated cost before you confirm.