diff --git a/.github/workflows/dashboard_refresh.yml b/.github/workflows/dashboard_refresh.yml new file mode 100644 index 0000000..8cb7632 --- /dev/null +++ b/.github/workflows/dashboard_refresh.yml @@ -0,0 +1,106 @@ +name: Dashboard Refresh + +# Re-ingests every registered instance (resolve its branch to one commit, read +# its summary at that SHA, validate, write receipts/ and the last-good +# snapshots/), re-renders dashboard.md / dashboard.html / badge.json / +# state.json, and commits them to main as github-actions[bot] when they +# changed. (Eyes/Cortex pattern.) +# +# Triggers: +# - repository_dispatch `pulse-refresh`: to be fired by each project repo's +# pages_dashboard.yml after it publishes a new summary (sender side is a +# follow-up in the project repo). The payload is only logged: the board +# always re-resolves the branch itself, so a dispatch can never make the +# dashboard disagree with the project's main. +# - a nightly cron: catches any dispatch that did not arrive. +# - push to main touching the registry or the reader, and workflow_dispatch. +# - pull_request: a dry run (ingest + render, no commit) so a reader change +# is exercised against the live feeds before it merges. +# +# Receipts and snapshots carry their `fetched_at` while nothing changes, the +# pages carry no wall-clock stamp, and state.json's `updated` moves only when +# the feed's content does, so a night with no new project commit commits +# nothing. A failed fetch keeps the committed snapshot (shown as cached, never +# re-aged). The body map is read from a checkout of PyAutoMind (public). The +# bot commit uses GITHUB_TOKEN, which never triggers other workflows, so after +# a commit this workflow dispatches pages_dashboard.yml explicitly. + +on: + repository_dispatch: + types: [pulse-refresh] + schedule: + - cron: "55 3 * * *" + workflow_dispatch: + push: + branches: [main] + paths: + - "registry.yaml" + - "pulse/**" + pull_request: + +permissions: + contents: write + actions: write + +# Every workflow in this repo that pushes to main shares one queue. +concurrency: + group: ${{ github.event_name == 'pull_request' && format('pulse-refresh-pr-{0}', github.ref) || 'pulse-main-writers' }} + cancel-in-progress: false + +jobs: + refresh: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Log the trigger + env: + PAYLOAD: ${{ toJson(github.event.client_payload) }} + run: | + echo "event: ${GITHUB_EVENT_NAME}" + if [ "${GITHUB_EVENT_NAME}" = "repository_dispatch" ]; then echo "payload: ${PAYLOAD}"; fi + + - name: PyAutoMind (the body map that resolves each instance's repo) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/PyAutoMind + path: _mind + + - name: Dependencies + run: python3 -m pip install --quiet pyyaml + + - name: Dry run (pull request) + if: github.event_name == 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + run: | + bin/pyauto-pulse board --mind _mind + git status --short + + - name: Ingest, render and commit the dashboard (only when changed) + if: github.event_name != 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + FILES="dashboard.md dashboard.html badge.json state.json receipts snapshots" + for attempt in 1 2 3; do + git fetch -q origin main && git reset -q --hard origin/main + bin/pyauto-pulse board --mind _mind + git add $FILES + if git diff --cached --quiet; then + echo "dashboard unchanged: nothing to commit" + exit 0 + fi + git commit -q -m "pulse: refresh dashboard (${GITHUB_EVENT_NAME}) [skip ci]" + if git push -q origin HEAD:main; then + gh workflow run pages_dashboard.yml --ref main \ + || echo "::warning::could not dispatch pages_dashboard.yml; Pages lags until its next trigger" + exit 0 + fi + echo "push rejected (main moved); retrying on the new tip" + done + echo "::error::could not push the refreshed dashboard after 3 attempts" + exit 1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..a4427fe --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,89 @@ +# lint.yml: the PR / push-to-main gate for the PyAutoPulse organ. +# +# 1. ruff check + ruff format --check +# 2. pytest tests/ (hermetic: registry, summary reader, ingest + receipts, +# board, CLI — every network call is refused; state.json is validated +# against the Brain contract because PyAutoBrain is checked out below) +# 3. `bin/pyauto-pulse check --offline`: registry valid against the Mind body +# map, every committed snapshot still validates under this reader, each +# receipt records its snapshot's commit, the committed dashboard was +# built from those receipts, and state.json meets the Brain contract. +# Offline on purpose: a project commit landing mid-PR must not redden an +# unrelated organ PR (dashboard_refresh.yml re-reads the network nightly). +# 4. lychee link-rot over the prose *.md. raw.githubusercontent.com, +# dashboard.md (hundreds of commit-pinned evidence links), the organ's own +# Pages URL (until Pages is enabled and the first deploy lands) and +# GitHub issue/pull/commit URLs are excluded. + +name: lint + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: PyAutoMind (the body map that resolves each instance's repo) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/PyAutoMind + path: _mind + + - name: PyAutoBrain (the state.json contract validator) + uses: actions/checkout@v4 + with: + repository: ${{ github.repository_owner }}/PyAutoBrain + path: _brain + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install tools + run: | + python -m pip install --quiet ruff pytest pyyaml + curl -sSfL https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz \ + | tar -xz -C /usr/local/bin --strip-components=1 lychee-x86_64-unknown-linux-gnu/lychee + + - name: ruff check + run: ruff check --exclude _mind --exclude _brain . + + - name: ruff format --check + run: ruff format --check --exclude _mind --exclude _brain . + + - name: pytest (hermetic) + env: + PYAUTO_BRAIN: ${{ github.workspace }}/_brain + run: python -m pytest tests -q + + - name: pyauto-pulse check --offline + env: + PYAUTO_BRAIN: ${{ github.workspace }}/_brain + run: bin/pyauto-pulse check --offline --mind _mind + + - name: lychee (markdown link-rot) + env: + # github.com serves 503 to unauthenticated page fetches (rate limit); + # with a token lychee checks github.com links through the API instead. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + lychee \ + --github-token "${GITHUB_TOKEN}" \ + --exclude '^https://raw\.githubusercontent\.com/' \ + --exclude '^https://pyautolabs\.github\.io/PyAutoPulse' \ + --exclude '^https://github\.com/.*/(issues|pull|commit|releases)/' \ + --no-progress \ + --accept '200..=299,429' \ + --max-redirects 5 \ + $(find . -name '*.md' -not -name 'dashboard.md' -not -path './.claude/*' -not -path './.git/*' -not -path './_mind/*' -not -path './_brain/*') diff --git a/.github/workflows/pages_dashboard.yml b/.github/workflows/pages_dashboard.yml new file mode 100644 index 0000000..8ceca7f --- /dev/null +++ b/.github/workflows/pages_dashboard.yml @@ -0,0 +1,62 @@ +name: Pages Dashboard + +# Publishes the generated `dashboard.html` as this repo's GitHub Pages index: +# https://pyautolabs.github.io/PyAutoPulse/ +# +# The page is rendered by `bin/pyauto-pulse board` and kept fresh by +# dashboard_refresh.yml. This workflow only publishes it, with badge.json (the +# one-line headline other boards read) and state.json (the organ-cockpit feed, +# contract PyAutoBrain/board/state_schema.json) beside it, and nothing else: +# no summary, receipt or snapshot is copied into the site, and every evidence +# link points at the project repo at the captured commit. (Eyes/Cortex pattern.) + +on: + push: + branches: [main] + paths: + - "dashboard.html" + - "badge.json" + - "state.json" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + # enablement: true creates the Pages site on first run where the token + # may; otherwise enable Pages (source: GitHub Actions) once by hand. + - uses: actions/configure-pages@v5 + with: + enablement: true + - name: Stage the dashboard as the site index + run: | + mkdir -p _site + cp dashboard.html _site/index.html + cp badge.json _site/badge.json + cp state.json _site/state.json + # The contract is owned by the Brain (board/_state.py); the Pulse only + # emits it. A feed the cockpit cannot read fails loudly here. + - uses: actions/checkout@v4 + with: + repository: PyAutoLabs/PyAutoBrain + path: PyAutoBrain + - name: Validate the cockpit feed against the Brain contract + run: python3 PyAutoBrain/board/_state.py _site/state.json + - uses: actions/upload-pages-artifact@v3 + with: + path: _site + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 7765e61..ace699e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,10 @@ venv/ # Pages staging _site/ + +# PyAutoMind checkout the refresh workflow reads the body map from +_mind/ + +# Half-written receipt/snapshot files (written then renamed into place) +receipts/*.tmp +snapshots/*.tmp diff --git a/AGENTS.md b/AGENTS.md index bf89c2a..473ff91 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,14 +4,13 @@ This file is for AI coding agents (Claude Code, Codex, Cursor, etc.) and humans discovering this repository. PyAutoPulse is the **Pulse** organ of the PyAuto organism — where the organism feels how fast it runs. It is the cross-project profiling dashboard over the `_profiling` project repos (today -`autolens_profiling`): it will own the profiling instance registry, the -versioned `profiling-summary` read contract, the ingest receipts (resolved -commit per project per render) and the Pages board. It validates the exchange -contract only and never judges a timing — the Brain's profiling conductor -(`triage`) does. The project repos keep their producers, results, drift policy -and their own Pages page. This repo is a stub: the registry, reader, board and -workflows arrive in phase 2 of the `profiling-organ-birth` epic. Design: -`PyAutoBrain/docs/research/profiling_inference_organs.md`. +`autolens_profiling`): it owns the profiling instance registry, the versioned +`profiling-summary` read contract, the ingest receipts (resolved commit per +project per render) and the Pages board. It validates the exchange contract +only and never judges a timing — the Brain's profiling conductor (`triage`) +does. The project repos keep their producers, results, drift policy and their +own Pages page. Design: `PyAutoBrain/docs/research/profiling_inference_organs.md`; +the contract as read and every file format: `REFERENCE.md`. **You are one organ of the PyAuto organism** — an agentic ecosystem for @@ -72,3 +71,107 @@ body and hands them to the human (sessions cannot create Discussions). Only the development flow — Mind prompt → `/start_dev` → `/create_issue` → one issue per task → PR — opens issues here. Why: `PyAutoMind/policy/community_surface.md`. + +## What this repo is + +The design has **two layers** (`profiling_inference_organs.md`, PyAutoBrain#444): + +- **Project repos** `_profiling` run the producers, keep the result JSONs, + own the drift policy and the meaning of every number, render their own Pages + page, and publish one **summary** file behind the `profiling-summary` + contract. Registered today: `lens` → `autolens_profiling` + (`dashboard/summary.json`, contract documented in that repo's + `dashboard/README.md`). +- **This organ** reads each registered summary at one resolved commit, + validates the exchange contract, records a receipt, and publishes the + cross-project board (`dashboard.md` + `dashboard.html` on Pages, with + `state.json` for the Brain cockpit and `badge.json`). + +## What this organ owns (its growth-rule state) + +| State | File | Written by | +|---|---|---| +| Instance registry | `registry.yaml` | a human, through the dev flow | +| The read contract as this organ implements it | `pulse/summary.py` + `REFERENCE.md` | the dev flow (reader first, producer second on a version bump) | +| Ingest receipts — the resolved commit, fetch time, outcome and errors per instance | `receipts/.json` | `bin/pyauto-pulse board` / `fetch` / `check` | +| Last-good snapshots — the summary as captured, with its commit and fetch time | `snapshots/.json` | the same, on a good read only | +| The board | `dashboard.md`, `dashboard.html`, `state.json`, `badge.json` | `bin/pyauto-pulse board` (and `dashboard_refresh.yml`) | + +Repository location and GitHub identity are **not** owned here: a registry row +names its project by its PyAutoMind body-map identity (`repo`), and `path` / +`github` are read from `PyAutoMind/repos.yaml` at run time (`--mind PATH`, +else `$PYAUTO_MIND`, else `$PYAUTO_ROOT/organs/PyAutoMind` or +`$PYAUTO_ROOT/PyAutoMind`, else beside this organ). There is no second +catalogue of repositories. + +## Boundary (what this organ never does) + +From the spec's "Profiling domain contract", verbatim: + +> A memory value cannot enter a seconds series, and a component timing cannot be +> presented as a full likelihood cost. + +> The organ displays project-supplied drift candidates and provenance. It does not +> move pins, combine unmatched timings, apply the compile threshold to runtime, +> compute an ecosystem-wide speed score or issue a Heart verdict. A drift item links +> to its pair of records and offers the existing profiling triage door. A confirmed +> library defect subsequently takes the normal Mind development route. + +In practice: + +- **Recomputes no ratio.** The board prints the producer's own `comparisons[]` + ratio and status verbatim; it never divides two measurements. +- **Never combines unmatched records.** A comparison whose two records differ in + axis, or in hardware identity (`device`, `backend`, `precision`, `host`), is + listed as *refused by the reader* with its reason and no ratio; accepted + pairs are grouped by hardware so changed hardware is always a separate group. +- **Ranks nothing across projects** — no league table, no speed score. +- **Issues no verdict.** `state.json` summarises this organ's monitoring scope + only, never release readiness (that is the Heart's). +- **Judges nothing.** The Brain's profiling conductor is the only judge: a + drift item's only handoff is the manual `/profiling triage ` + prompt (`kind: prompt`, `safety: scientific_judgement`). Fetching or + rendering never submits a job, re-pins a baseline, logs a lesson, edits + source or grants approval. +- **Imports no scientific library.** The reader is PyYAML + stdlib. + +## Three notions, kept apart + +Every row and every detail section keeps three separate labels: + +1. **Integrity** — transport and schema: `ok`, `invalid`, `unavailable`, + `unsupported`, or `cached` (the latest fetch failed and the last good + capture is shown with its *original* evidence and fetch times plus the new + error; no render ever re-ages it). +2. **Freshness** — against the producer's own `valid_until`. When the producer + declares none, the board says "freshness policy unspecified" with the + evidence's age; it never invents a TTL. +3. **Qualification** — the producer's own `qualified` flags, counted. Unknown + provenance is shown unqualified, never dropped; healthy transport never + makes unknown quality green. A valid empty feed reads "no measurements", + never "all measurements passed". + +## Adding an instance + +1. The project repo publishes a summary behind a contract version this reader + supports, documented in that repo. +2. Add a validated fixture under `tests/fixtures/` showing its conventions read + through the same code path (no project-specific branching — see + `second_producer.json`). +3. Add one `registry.yaml` row (`instance`, `repo` = body-map identity, + `summary_path`, `supported_schema`, `dashboard_url`, `library_refs`, + `cortex_project`). One summary is registered once; discovery by a + `*_profiling` name alone is insufficient. +4. `bin/pyauto-pulse board` and commit the board, receipt and snapshot. + +## Commands + +```bash +bin/pyauto-pulse check # registry + body map, ingest at one commit, receipt, dashboard current, state.json → "check: OK" +bin/pyauto-pulse check --offline # the same over the committed receipts + snapshots (CI) +bin/pyauto-pulse board # ingest, then render dashboard.md/.html, badge.json, state.json +bin/pyauto-pulse census # one line per instance from the committed snapshots +bin/pyauto-pulse fetch [--instance K] # ingest + receipt only +``` + +Before a PR: `ruff check . && ruff format --check . && pytest -q tests && bin/pyauto-pulse check --offline`. diff --git a/README.md b/README.md index 9353dac..504683c 100644 --- a/README.md +++ b/README.md @@ -3,25 +3,46 @@ The **Pulse** organ of the [PyAuto organism](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/ORGANISM.md): where the organism feels how fast it runs. +**Board:** + PyAutoPulse is the cross-project profiling dashboard over the `_profiling` project repos (today [autolens_profiling](https://github.com/PyAutoLabs/autolens_profiling)). It owns: -- the **instance registry** — which projects publish a profiling summary, where, - under which contract version; +- the **instance registry** (`registry.yaml`) — which projects publish a + profiling summary, where, under which contract version; each project is named + by its PyAutoMind body-map identity, never a second repository catalogue; - the versioned **`profiling-summary` read contract** — v1 is live at - `autolens_profiling/dashboard/summary.json`; -- the **ingest receipts** — the resolved commit per project per render; -- the cross-project **Pages board**. + `autolens_profiling/dashboard/summary.json`, documented in that repo's + [dashboard/README.md](https://github.com/PyAutoLabs/autolens_profiling/blob/main/dashboard/README.md); +- the **ingest receipts** (`receipts/`) — the one commit each project was read + at, per render — and the last-good **snapshots** (`snapshots/`), shown as + *cached* when a later fetch fails; +- the cross-project **Pages board** (`dashboard.md`, `dashboard.html`, plus + `state.json` for the Brain cockpit and `badge.json`). It validates the exchange contract only. It never moves pins, combines unmatched timings, applies the compile threshold to runtime, computes an ecosystem-wide speed score or issues a release-health verdict, and it never judges a timing — -the Brain's profiling conductor does. The project repos keep their producers, -results, drift policy and their own Pages page. +the Brain's profiling conductor does (`/profiling triage `). The +project repos keep their producers, results, drift policy and their own Pages page. + +## Run it + +Python 3.11+ with PyYAML; no scientific library is imported. A PyAutoMind +checkout supplies the body map (`--mind PATH`, `$PYAUTO_MIND`, or beside this +repo). + +```bash +bin/pyauto-pulse check # ingest at one resolved commit, validate, write receipts → "check: OK" +bin/pyauto-pulse board # ingest, then render the board +bin/pyauto-pulse census # one line per instance from the committed snapshots +bin/pyauto-pulse fetch --instance lens +pytest -q tests # hermetic: no network +``` -**Status:** stub. The registry, reader, receipts, board and workflows arrive in -phase 2 of the `profiling-organ-birth` epic. Design: +Formats, the contract as read and every rule: [REFERENCE.md](REFERENCE.md). +Boundaries: [AGENTS.md](AGENTS.md). Design: [profiling_inference_organs.md](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/docs/research/profiling_inference_organs.md). ## License diff --git a/REFERENCE.md b/REFERENCE.md new file mode 100644 index 0000000..e83aff7 --- /dev/null +++ b/REFERENCE.md @@ -0,0 +1,180 @@ +# PyAutoPulse — reference + +The registry schema, the `profiling-summary` v1 contract as this organ reads +it, and the formats of the receipts, snapshots, board markers and cockpit feed. +Prose boundaries live in [AGENTS.md](AGENTS.md); the design is +[profiling_inference_organs.md](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/docs/research/profiling_inference_organs.md). + +## Registry (`registry.yaml`, `schema: 1`) + +One row per instance under `instances:`. Unknown fields are refused. + +| Field | Required | Meaning | +|---|---|---| +| `instance` | yes | Stable key within the organ, `^[a-z][a-z0-9_-]*$`, unique. | +| `repo` | yes | A PyAutoMind body-map identity (`repos.yaml` key). `path` and `github` are read from the body map at load time and **may not** be written in the row. | +| `summary_path` | yes | Repository-relative path of the producer's summary (no `/`-prefix, `..`, URL). | +| `supported_schema` | yes | `@` the reader expects, e.g. `profiling-summary@1`. | +| `dashboard_url` | yes | The project's own human-facing page (`https://`). | +| `library_refs` | no | Body-map identities the project exercises (each must be in the body map). | +| `cortex_project` | no | An existing Cortex key, or `null`. | + +Further rules: the same `(repo, summary_path)` may be registered once (disjoint +scopes; no inflated coverage). Every ingest reads branch `main`. + +Body map resolution order: `--mind PATH` (must hold `repos.yaml`, never a +silent fall-through), `$PYAUTO_MIND`, `$PYAUTO_ROOT/organs/PyAutoMind`, +`$PYAUTO_ROOT/PyAutoMind`, then beside this organ (grouped `organs/` or flat +task-bundle layout). No body map → an error, never a guess. + +## `profiling-summary` v1, as read here + +The producer documents the contract +([autolens_profiling `dashboard/README.md`](https://github.com/PyAutoLabs/autolens_profiling/blob/main/dashboard/README.md)); +this is what `pulse/summary.py` enforces. Additive fields are ignored. + +**Support.** `(schema, version)` must be `("profiling-summary", 1)` *and* match the +registry row's `supported_schema`; otherwise the outcome is **unsupported** and +nothing else is validated. + +**Envelope** — required: `schema, version, project, scope, generated_at, +evidence_updated_at, producer_revision, comparison_policy, coverage, records, +comparisons, limitations`. A missing field makes the feed **invalid**. + +- `project`, `scope`: non-empty strings. +- `generated_at`: ISO-8601 UTC (`Z` or `+00:00`). +- `evidence_updated_at`: ISO-8601 UTC, or `null` with a non-empty + `evidence_updated_at_reason`. +- `valid_until` (optional): `null` (= freshness policy unspecified) or ISO-8601 + UTC not before `evidence_updated_at`. +- `producer_revision`: 40-hex or `null` — the producer *code* revision, distinct + from the commit the organ resolved (which the receipt records). +- `comparison_policy`: an object with a non-empty `id`. +- `coverage`: `expected` object; `observed` object of non-negative integers; + `excluded` list of `{id, reason, evidence: {path}}` with safe paths. +- `limitations`: list of non-empty strings, shown verbatim. + +**Records** — each an object with: + +- `id`: non-empty, unique in the file (grammar `@`). +- `axis` ∈ `runtime | compile | breakdown | memory`, and `unit` belongs to its axis + (`s` for the time axes; `B/KB/MB/GB/KiB/MiB/GiB` for memory). A memory unit in a + seconds series — or the reverse — is refused. +- `measurement`: non-empty object of finite numbers or `null`, at least one non-null + (`NaN`/`inf`/booleans refused). +- `identity`: object carrying `device`, `backend`, `precision` (values may be + `null`; absence is an error). +- `provenance`: object with boolean `has_provenance` and `qualified`, a `host` + key (null if unknown); numeric fields finite. A record with + `has_provenance: false` is shown and counted **unqualified**, never dropped. +- `evidence.path`: repo-relative (no leading `/`, `..`, `\`, URL); resolved + against the commit the organ captured. + +**Comparisons** — each an object with a unique non-empty `comparison_key`, +`policy` equal to `comparison_policy.id`, `axis` in the axis table, a `metric`, +`status` ∈ `drifted | improved | flat | insufficient`, finite-or-null `ratio`, +boolean `qualified`, `reasons` list of strings, `baseline`/`candidate` a release +reference or `null`. + +**Pairing (display rule, not a feed error).** Each comparison's endpoints +resolve to records `@` / `@`. A pair is +**refused by the reader** — listed apart with its reason, ratio not shown — +when an endpoint is not among the records, when the records' axes differ from +each other or from the comparison's, or when their hardware identity +(`device`, `backend`, `precision`, `host`) differs. A host is compared only when +both records name one. Accepted pairs are grouped by `device · backend · +precision`, in producer order (never sorted by ratio). + +**Outcomes.** `ok` · `invalid` (not JSON, or contract breaks) · `unsupported` +(schema/version) · `unavailable` (transport: API or raw file unreadable). + +## Ingest + +1. `GET https://api.github.com/repos///commits/main` → one 40-hex SHA + (stdlib `urllib`, 20 s timeout, `User-Agent`, `Authorization: Bearer $GH_TOKEN` + on API calls only, when set). +2. `GET https://raw.githubusercontent.com////`. +3. Validate; write the receipt; on `ok` also write the snapshot. + +`--offline` reads the committed receipt + snapshot and writes nothing. `--from +[INSTANCE=]PATH` reads a local checkout (or the file), reports its `HEAD` and +dirty state (`git status --porcelain`), is labelled "local checkout", and +writes **no** receipt or snapshot. + +### Receipt — `receipts/.json` + +```json +{ + "instance": "lens", "repo": "autolens_profiling", "github": "PyAutoLabs/autolens_profiling", + "branch": "main", "resolved_commit": "<40-hex or null>", "summary_path": "dashboard/summary.json", + "source": "remote", "fetched_at": "", "outcome": "ok|invalid|unavailable|unsupported", + "schema": "profiling-summary", "version": 1, "record_count": 159, + "errors": [], "cached_from": "" +} +``` + +### Snapshot — `snapshots/.json` + +`{instance, repo, github, summary_path, commit, fetched_at, summary}` — the last +good summary verbatim, with the commit and time it was captured. Written only on +an `ok` read; a failed read leaves it untouched, and the board shows it as +**cached** with its original `commit`, `fetched_at` and the summary's own +`evidence_updated_at`, plus the new receipt's error. + +**Carried times.** A receipt or snapshot is rewritten only when something other +than `fetched_at` changes, so `fetched_at` is the time an outcome at a commit +was *first* observed. A nightly refresh against an unchanged project commits +nothing; a new project commit moves both. + +## Board + +- `dashboard.md` / `dashboard.html`: the project table (Project, Scope, + Evidence, Last fetch, Coverage, **Integrity**, **Freshness**, + **Qualification**, Links), then per instance the producer's + limitations, excluded rows and comparisons by hardware group, each comparison + linking its two records' evidence at the captured commit and carrying + `/profiling triage `. Freshness without a policy is shown as + "freshness policy unspecified · age N d at fetch " (the HTML adds a live + "N d today"); a passed `valid_until` reads "stale". +- Instance marker (what `check` compares to the receipt): + ``. +- `badge.json`: shields endpoint, label `pulse`, message = the state headline. +- `state.json`: the Brain cockpit feed v1 (`PyAutoBrain/board/_state.py`): + `organ: pulse`, `repo: PyAutoPulse`, `pages_url: https://pyautolabs.github.io/PyAutoPulse/`, + headline `N project(s) · R records · C cached[ · F failed]`; `updated` moves only + when the content does. + +| Item | Severity | +|---|---| +| latest read `invalid`/`unsupported`, or `unavailable` with no capture | red | +| `unavailable` with a cached capture | yellow | +| `valid_until` passed; or no policy and evidence older than 90 d (presentation only) | yellow | +| valid empty feed ("no measurements") | yellow | +| records the producer marks unqualified | yellow | +| `drifted` comparison, qualified | yellow, with the triage action | +| `drifted` comparison, unqualified (a contextual flag) | info, with the triage action | +| local read; census line | info | + +Status: red if any red item, else yellow if any yellow, else green. A drift +item's actions are `{id: triage, kind: prompt, safety: scientific_judgement, +target: "/profiling triage "}` and a read-only link to the +candidate's evidence at the captured commit. + +## CLI + +| Command | Does | +|---|---| +| `check [--offline] [--from …] [--mind PATH]` | body map + registry valid; each instance ingests (online: resolves, fetches, writes the receipt) and validates; each receipt records its snapshot commit; dashboard markers match the receipts; `state.json` meets the Brain contract (validator found at `$PYAUTO_BRAIN`, else beside this organ). Prints `check: OK` / `check: FAIL`. | +| `board [--offline] [--from …] [--mind PATH]` | ingest, then write the four board files. | +| `census [--mind PATH]` | one line per instance from the committed snapshots: records · comparisons · limitations · qualified · integrity · commit. | +| `fetch [--instance K] [--mind PATH]` | ingest + receipt only; exit 1 when a fetch fails. | + +## Workflows + +- `lint.yml` — ruff, hermetic pytest, `check --offline` (Mind + Brain checked out), lychee. +- `dashboard_refresh.yml` — `repository_dispatch: pulse-refresh`, nightly 03:55 UTC, + `workflow_dispatch`, push to main on `registry.yaml`/`pulse/**` (commit + push, 3 + attempts, then dispatch `pages_dashboard.yml`), and a no-commit dry run on PRs. + Main writers share the concurrency group `pulse-main-writers`. +- `pages_dashboard.yml` — publishes `dashboard.html` as `index.html` with `badge.json` + and `state.json`, after validating the feed with `PyAutoBrain/board/_state.py`. diff --git a/badge.json b/badge.json new file mode 100644 index 0000000..3af2113 --- /dev/null +++ b/badge.json @@ -0,0 +1,6 @@ +{ + "schemaVersion": 1, + "label": "pulse", + "message": "1 project \u00b7 159 records \u00b7 0 cached", + "color": "yellow" +} diff --git a/bin/pyauto-pulse b/bin/pyauto-pulse new file mode 100755 index 0000000..cbaaae6 --- /dev/null +++ b/bin/pyauto-pulse @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +"""pyauto-pulse: check | board | census | fetch. See `pyauto-pulse --help` and README.md.""" + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from pulse.cli import main # noqa: E402 + +raise SystemExit(main()) diff --git a/dashboard.html b/dashboard.html new file mode 100644 index 0000000..b41d9f4 --- /dev/null +++ b/dashboard.html @@ -0,0 +1,50 @@ + +PyAutoPulse dashboard

PyAutoPulse

Measure. Trace. Compare.

The cross-project view of the organism's profiling. Each <lib>_profiling project repo runs its producers, keeps its results and drift policy, and publishes a profiling-summary file. This page reads each file at one resolved commit, validates the exchange contract and shows what the producer says: it recomputes no ratio, combines no timings whose axis or hardware differs, ranks nothing across projects and issues no verdict. Judgment belongs to the Brain's profiling conductor (/profiling triage).

1Projects
159Records
145Comparisons
0Drifted
0Refused pairs
0Cached
0Failed

Projects

ProjectScopeEvidenceLast fetchCoverageIntegrityFreshnessQualificationLinks
lens autolens_profilingrelease-runtime2026-08-172026-10-02 @ d9f385f0145 series · 159 points · 4 releases · 61 cells · 6 excludedokfreshness policy unspecified · age 46 d at fetch 2026-10-022/159 records · 0/145 comparisons qualifieddashboard · repo · receipt

Three notions are kept apart: integrity is whether the file was fetched and meets the contract; freshness is the evidence's age against the producer's own valid_until (none declared → "freshness policy unspecified"); qualification is the producer's own flag on each record and comparison. Healthy transport never makes unknown quality green.

lens · autolens_profiling

Project autolens_profiling, scope release-runtime, read from PyAutoLabs/autolens_profiling dashboard/summary.json at d9f385f0; producer revision 227b5c91; generated 2026-09-30T19:43:00Z; policy runtime-drift-2x-1ms. Project dashboard · receipt.

Integrityok
Freshnessfreshness policy unspecified · age 46 d at fetch 2026-10-02 (evidence 2026-08-17)
Qualification2/159 records · 0/145 comparisons qualified

Limitations (the producer's own)

  • runtime axis only: compile times, VRAM and per-step component timings are not in this feed
  • evidence_updated_at is the newest release date encoded in a measured library version; result rows do not record measurement wall-clock time
  • valid_until is null: this project declares no freshness policy for release trends
  • vmap_per_call_s is null where a row carries no vmap block
  • rows without a device.provenance block (pre-autolens_profiling#342) are unqualified
  • 6 row(s) above the load-average cap 8 are listed under coverage.excluded and never enter records

Excluded by the producer

  • breakdown:interferometer/sdp81/delaunay/sdp81:hpc_a100_fp64@2026.8.17.1: loadavg 65.7 above the cap 8 (evidence)
  • breakdown:interferometer/sdp81/delaunay_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1: loadavg 68.3 above the cap 8 (evidence)
  • breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64@2026.8.17.1: loadavg 55.7 above the cap 8 (evidence)
  • breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64_sparse@2026.8.17.1: loadavg 55.7 above the cap 8 (evidence)
  • breakdown:interferometer/sdp81/pixelization/sdp81:hpc_a100_fp64@2026.8.17.1: loadavg 65.7 above the cap 8 (evidence)
  • breakdown:interferometer/sdp81/pixelization_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1: loadavg 68.3 above the cap 8 (evidence)

Comparisons on cpu · cpu · float64

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
runtime:imaging/delaunay/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 [local_cpu_fp64] → 2026.8.17.10.27improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
runtime:imaging/delaunay/hst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/jwst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/jwst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay_nn/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay_numba/euclid:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay_numba/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/ao:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 [local_cpu_fp64] → 2026.8.17.10.671flatnobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
runtime:imaging/mge/hst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/jwst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/jwst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge_mass_jax/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 [local_cpu_fp64] → 2026.8.17.10.232improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
runtime:imaging/pixelization/hst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/jwst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/jwst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization_numba/euclid:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization_numba/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization_numba_mge_mass/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/delaunay/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/mge/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/pixelization/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:cluster/image_plane:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.23.1 → 2026.8.17.10.469improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:cluster/source_plane:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 → 2026.7.23.11.469flatnobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/delaunay/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 → 2026.8.17.10.331improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/delaunay/hst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s2026.5.29.4 → 2026.7.6.6491.108flatnobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/delaunay_nn/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay_numba/euclid:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay_numba/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/mge/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 → 2026.8.17.10.225improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/pixelization/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s2026.7.6.649 → 2026.8.17.10.393improvednobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/pixelization/hst:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s2026.5.29.4 → 2026.7.6.6491.139flatnobaseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row)
breakdown:imaging/pixelization_numba/euclid:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/pixelization_numba/hst:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_direct_conv/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_direct_conv/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_jax/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_jax/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_reference/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_reference/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_source_loop/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_symmetric/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba_two_stage/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/alma:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/alma_high:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/sma:local_cpu_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge_dft/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_direct_conv/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_direct_conv/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_jax/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_jax/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_reference/alma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba_reference/sma:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:point_source_image/image_plane/simple:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:point_source_source/source_plane/simple:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only

Comparisons on cpu · cpu · mixed

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
runtime:imaging/delaunay/hst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/hst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/jwst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/jwst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/ao:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/hst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/hst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/jwst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/mge/jwst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/hst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/hst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/jwst:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/jwst:local_cpu_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/delaunay/alma:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/delaunay/sma:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/mge/sma:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:interferometer/pixelization/sma:local_cpu_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only

Comparisons on a100 · gpu · float64

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
runtime:imaging/delaunay/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay_nn/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/delaunay_nn/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:imaging/pixelization/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:point_source_source/source_plane_solved:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:datacube/delaunay/alma_high:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/mge/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/pixelization/hst:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/pixelization/hst:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay/alma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/alma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/mge/alma:hpc_a100_fp64_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization/alma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/delaunay/sma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/mge/sma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/pixelization/sma:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:point_source_source/source_plane/simple:hpc_a100_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only

Comparisons on cpu · backend unknown · float64

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
runtime:point_source_image/image_plane_solved:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
runtime:point_source_source/source_plane_solved:local_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only

Comparisons on ral_cpu · cpu · float64

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:cluster/image_plane:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/delaunay/alma_high:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/delaunay_numba/alma_high:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/pixelization/alma_high:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/pixelization_numba/alma_high:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay/alma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay_numba/alma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization/alma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization_numba/alma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/delaunay/sma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/delaunay_numba/sma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/pixelization/sma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/pixelization_numba/sma:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:point_source_image/image_plane/simple:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:point_source_source/source_plane/simple:hpc_ral_cpu_fp64runtime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only

Comparisons on a100 · gpu · mixed

ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
breakdown:datacube/delaunay/alma_high:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay/hst:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/delaunay/hst:hpc_a100_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/pixelization/hst:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:imaging/pixelization/hst:hpc_a100_mp_sparseruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/delaunay/alma:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/mge/jvla:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/pixelization/alma:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/delaunay/sma:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
breakdown:interferometer/sma/pixelization/sma:hpc_a100_mpruntime-drift-2x-1msruntime · single_jit_s— → ——insufficientnoone release only
diff --git a/dashboard.md b/dashboard.md new file mode 100644 index 0000000..ed37a7b --- /dev/null +++ b/dashboard.md @@ -0,0 +1,227 @@ +# PyAutoPulse — profiling dashboard + + + +The cross-project view of the organism's profiling. Each `_profiling` project repo runs its producers, keeps its results and drift policy, and publishes a `profiling-summary` file. This page reads each file at one resolved commit, validates the exchange contract and shows what the producer says: it recomputes no ratio, combines no timings whose axis or hardware differs, ranks nothing across projects and issues no verdict. Judgment belongs to the Brain's profiling conductor (`/profiling triage`). +Live page: [https://pyautolabs.github.io/PyAutoPulse/](https://pyautolabs.github.io/PyAutoPulse/). + +| Where | Count | +|-------|------:| +| [Projects](#projects) | 1 | +| [Records](#projects) | 159 | +| [Comparisons](#projects) | 145 | +| [Drifted](#projects) | 0 | +| [Refused pairs](#projects) | 0 | +| [Cached](#projects) | 0 | +| [Failed](#projects) | 0 | + +## Projects + +| Project | Scope | Evidence | Last fetch | Coverage | Integrity | Freshness | Qualification | Links | +|---|---|---|---|---|---|---|---|---| +| [lens](#lens) (autolens_profiling) | release-runtime | 2026-08-17 | 2026-10-02 @ d9f385f0 | 145 series · 159 points · 4 releases · 61 cells · 6 excluded | ok | freshness policy unspecified · age 46 d at fetch 2026-10-02 | 2/159 records · 0/145 comparisons qualified | [dashboard](https://pyautolabs.github.io/autolens_profiling/) · [repo](https://github.com/PyAutoLabs/autolens_profiling) · [receipt](https://github.com/PyAutoLabs/PyAutoPulse/blob/main/receipts/lens.json) | + +Three notions are kept apart: **integrity** is whether the file was fetched and meets the contract; **freshness** is the evidence's age against the producer's own `valid_until` (none declared → "freshness policy unspecified"); **qualification** is the producer's own flag on each record and comparison. Healthy transport never makes unknown quality green. + +## lens + + + +Project `autolens_profiling`, scope `release-runtime`, read from [PyAutoLabs/autolens_profiling](https://github.com/PyAutoLabs/autolens_profiling) `dashboard/summary.json` at [`d9f385f0`](https://github.com/PyAutoLabs/autolens_profiling/tree/d9f385f002803b822a6293d7bd20113d2611dca1); producer revision `227b5c91`; generated 2026-09-30T19:43:00Z; comparison policy `runtime-drift-2x-1ms`. [Project dashboard](https://pyautolabs.github.io/autolens_profiling/) · [receipt](https://github.com/PyAutoLabs/PyAutoPulse/blob/main/receipts/lens.json). + +- **Integrity:** ok +- **Freshness:** freshness policy unspecified · age 46 d at fetch 2026-10-02 (evidence 2026-08-17) +- **Qualification:** 2/159 records · 0/145 comparisons qualified + +### lens / limitations + +- runtime axis only: compile times, VRAM and per-step component timings are not in this feed +- evidence_updated_at is the newest release date encoded in a measured library version; result rows do not record measurement wall-clock time +- valid_until is null: this project declares no freshness policy for release trends +- vmap_per_call_s is null where a row carries no vmap block +- rows without a device.provenance block (pre-autolens_profiling#342) are unqualified +- 6 row(s) above the load-average cap 8 are listed under coverage.excluded and never enter records + +### lens / excluded by the producer + +- `breakdown:interferometer/sdp81/delaunay/sdp81:hpc_a100_fp64@2026.8.17.1`: loadavg 65.7 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/delaunay_hpc_a100_fp64.json)) +- `breakdown:interferometer/sdp81/delaunay_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1`: loadavg 68.3 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/delaunay_numba_hpc_ral_cpu_fp64.json)) +- `breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64@2026.8.17.1`: loadavg 55.7 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/mge_hpc_a100_fp64.json)) +- `breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64_sparse@2026.8.17.1`: loadavg 55.7 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/mge_hpc_a100_fp64_sparse.json)) +- `breakdown:interferometer/sdp81/pixelization/sdp81:hpc_a100_fp64@2026.8.17.1`: loadavg 65.7 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/pixelization_hpc_a100_fp64.json)) +- `breakdown:interferometer/sdp81/pixelization_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1`: loadavg 68.3 above the cap 8 ([evidence](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/interferometer/sdp81/pixelization_numba_hpc_ral_cpu_fp64.json)) + +### lens / comparisons on cpu · cpu · float64 + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `runtime:imaging/delaunay/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649 [local_cpu_fp64]](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/delaunay/hst/comparison.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/delaunay/delaunay_likelihood_summary_hst_v2026.8.17.1.json) | 0.27 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage runtime:imaging/delaunay/hst:local_cpu_fp64` | +| `runtime:imaging/delaunay/hst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/hst:local_cpu_fp64_sparse` | +| `runtime:imaging/delaunay/jwst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/jwst:local_cpu_fp64` | +| `runtime:imaging/delaunay/jwst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/jwst:local_cpu_fp64_sparse` | +| `runtime:imaging/delaunay_nn/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay_nn/hst:local_cpu_fp64` | +| `runtime:imaging/delaunay_numba/euclid:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay_numba/euclid:local_cpu_fp64` | +| `runtime:imaging/delaunay_numba/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay_numba/hst:local_cpu_fp64` | +| `runtime:imaging/mge/ao:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/ao:local_cpu_fp64` | +| `runtime:imaging/mge/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649 [local_cpu_fp64]](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/mge/hst/comparison.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/mge/mge_likelihood_summary_hst_v2026.8.17.1.json) | 0.671 | flat | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage runtime:imaging/mge/hst:local_cpu_fp64` | +| `runtime:imaging/mge/hst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/hst:local_cpu_fp64_sparse` | +| `runtime:imaging/mge/jwst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/jwst:local_cpu_fp64` | +| `runtime:imaging/mge/jwst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/jwst:local_cpu_fp64_sparse` | +| `runtime:imaging/mge_mass_jax/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge_mass_jax/hst:local_cpu_fp64` | +| `runtime:imaging/pixelization/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649 [local_cpu_fp64]](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/pixelization/hst/comparison.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/runtime/imaging/pixelization/pixelization_likelihood_summary_hst_v2026.8.17.1.json) | 0.232 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage runtime:imaging/pixelization/hst:local_cpu_fp64` | +| `runtime:imaging/pixelization/hst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/hst:local_cpu_fp64_sparse` | +| `runtime:imaging/pixelization/jwst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/jwst:local_cpu_fp64` | +| `runtime:imaging/pixelization/jwst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/jwst:local_cpu_fp64_sparse` | +| `runtime:imaging/pixelization_numba/euclid:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization_numba/euclid:local_cpu_fp64` | +| `runtime:imaging/pixelization_numba/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization_numba/hst:local_cpu_fp64` | +| `runtime:imaging/pixelization_numba_mge_mass/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization_numba_mge_mass/hst:local_cpu_fp64` | +| `runtime:interferometer/delaunay/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/delaunay/sma:local_cpu_fp64` | +| `runtime:interferometer/mge/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/mge/sma:local_cpu_fp64` | +| `runtime:interferometer/pixelization/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/pixelization/sma:local_cpu_fp64` | +| `breakdown:cluster/image_plane:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.23.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/cluster/image_plane_breakdown_v2026.7.23.1.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/cluster/image_plane_local_cpu_fp64.json) | 0.469 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:cluster/image_plane:local_cpu_fp64` | +| `breakdown:cluster/source_plane:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/cluster/source_plane_breakdown_v2026.7.6.649.json) → [2026.7.23.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/cluster/source_plane_breakdown_v2026.7.23.1.json) | 1.469 | flat | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:cluster/source_plane:local_cpu_fp64` | +| `breakdown:imaging/delaunay/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/delaunay_breakdown_hst_v2026.7.6.649.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/delaunay_breakdown_hst_v2026.8.17.1.json) | 0.331 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:imaging/delaunay/hst:local_cpu_fp64` | +| `breakdown:imaging/delaunay/hst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.5.29.4](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/delaunay_breakdown_hst_v2026.5.29.4_sparse.json) → [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/delaunay_breakdown_hst_v2026.7.6.649_sparse.json) | 1.108 | flat | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:imaging/delaunay/hst:local_cpu_fp64_sparse` | +| `breakdown:imaging/delaunay_nn/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay_nn/hst:local_cpu_fp64` | +| `breakdown:imaging/delaunay_numba/euclid:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay_numba/euclid:local_cpu_fp64` | +| `breakdown:imaging/delaunay_numba/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay_numba/hst:local_cpu_fp64` | +| `breakdown:imaging/mge/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/mge_breakdown_hst_v2026.7.6.649.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/mge_breakdown_hst_v2026.8.17.1.json) | 0.225 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:imaging/mge/hst:local_cpu_fp64` | +| `breakdown:imaging/pixelization/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/pixelization_breakdown_hst_v2026.7.6.649.json) → [2026.8.17.1](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/pixelization_breakdown_hst_v2026.8.17.1.json) | 0.393 | improved | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:imaging/pixelization/hst:local_cpu_fp64` | +| `breakdown:imaging/pixelization/hst:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | [2026.5.29.4](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/pixelization_breakdown_hst_v2026.5.29.4_sparse.json) → [2026.7.6.649](https://github.com/PyAutoLabs/autolens_profiling/blob/d9f385f002803b822a6293d7bd20113d2611dca1/results/breakdown/imaging/pixelization_breakdown_hst_v2026.7.6.649_sparse.json) | 1.139 | flat | no | baseline row unqualified: no provenance block (pre-#342 row); candidate row unqualified: no provenance block (pre-#342 row) | `/profiling triage breakdown:imaging/pixelization/hst:local_cpu_fp64_sparse` | +| `breakdown:imaging/pixelization_numba/euclid:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization_numba/euclid:local_cpu_fp64` | +| `breakdown:imaging/pixelization_numba/hst:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization_numba/hst:local_cpu_fp64` | +| `breakdown:interferometer/delaunay/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay/alma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_direct_conv/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_direct_conv/alma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_direct_conv/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_direct_conv/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_jax/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_jax/alma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_jax/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_jax/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_reference/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_reference/alma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_reference/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_reference/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_source_loop/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_source_loop/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_symmetric/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_symmetric/sma:local_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba_two_stage/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba_two_stage/sma:local_cpu_fp64` | +| `breakdown:interferometer/mge/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/alma:local_cpu_fp64` | +| `breakdown:interferometer/mge/alma:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/alma:local_cpu_fp64_sparse` | +| `breakdown:interferometer/mge/alma_high:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/alma_high:local_cpu_fp64` | +| `breakdown:interferometer/mge/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/sma:local_cpu_fp64` | +| `breakdown:interferometer/mge/sma:local_cpu_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/sma:local_cpu_fp64_sparse` | +| `breakdown:interferometer/mge_dft/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge_dft/sma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization/alma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization/sma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba/sma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_direct_conv/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_direct_conv/alma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_direct_conv/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_direct_conv/sma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_jax/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_jax/alma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_jax/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_jax/sma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_reference/alma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_reference/alma:local_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba_reference/sma:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba_reference/sma:local_cpu_fp64` | +| `breakdown:point_source_image/image_plane/simple:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:point_source_image/image_plane/simple:local_cpu_fp64` | +| `breakdown:point_source_source/source_plane/simple:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:point_source_source/source_plane/simple:local_cpu_fp64` | + +### lens / comparisons on cpu · cpu · mixed + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `runtime:imaging/delaunay/hst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/hst:local_cpu_mp` | +| `runtime:imaging/delaunay/hst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/hst:local_cpu_mp_sparse` | +| `runtime:imaging/delaunay/jwst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/jwst:local_cpu_mp` | +| `runtime:imaging/delaunay/jwst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/jwst:local_cpu_mp_sparse` | +| `runtime:imaging/mge/ao:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/ao:local_cpu_mp` | +| `runtime:imaging/mge/hst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/hst:local_cpu_mp` | +| `runtime:imaging/mge/hst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/hst:local_cpu_mp_sparse` | +| `runtime:imaging/mge/jwst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/jwst:local_cpu_mp` | +| `runtime:imaging/mge/jwst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/mge/jwst:local_cpu_mp_sparse` | +| `runtime:imaging/pixelization/hst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/hst:local_cpu_mp` | +| `runtime:imaging/pixelization/hst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/hst:local_cpu_mp_sparse` | +| `runtime:imaging/pixelization/jwst:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/jwst:local_cpu_mp` | +| `runtime:imaging/pixelization/jwst:local_cpu_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/jwst:local_cpu_mp_sparse` | +| `runtime:interferometer/delaunay/alma:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/delaunay/alma:local_cpu_mp` | +| `runtime:interferometer/delaunay/sma:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/delaunay/sma:local_cpu_mp` | +| `runtime:interferometer/mge/sma:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/mge/sma:local_cpu_mp` | +| `runtime:interferometer/pixelization/sma:local_cpu_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:interferometer/pixelization/sma:local_cpu_mp` | + +### lens / comparisons on a100 · gpu · float64 + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `runtime:imaging/delaunay/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/hst:hpc_a100_fp64` | +| `runtime:imaging/delaunay/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay/hst:hpc_a100_fp64_sparse` | +| `runtime:imaging/delaunay_nn/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay_nn/hst:hpc_a100_fp64` | +| `runtime:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse` | +| `runtime:imaging/pixelization/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/hst:hpc_a100_fp64` | +| `runtime:imaging/pixelization/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:imaging/pixelization/hst:hpc_a100_fp64_sparse` | +| `runtime:point_source_source/source_plane_solved:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:point_source_source/source_plane_solved:hpc_a100_fp64` | +| `breakdown:datacube/delaunay/alma_high:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:datacube/delaunay/alma_high:hpc_a100_fp64` | +| `breakdown:imaging/delaunay/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay/hst:hpc_a100_fp64` | +| `breakdown:imaging/delaunay/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay/hst:hpc_a100_fp64_sparse` | +| `breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64` | +| `breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse` | +| `breakdown:imaging/mge/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/mge/hst:hpc_a100_fp64` | +| `breakdown:imaging/pixelization/hst:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization/hst:hpc_a100_fp64` | +| `breakdown:imaging/pixelization/hst:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization/hst:hpc_a100_fp64_sparse` | +| `breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_fp64` | +| `breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64` | +| `breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64_sparse` | +| `breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_fp64` | +| `breakdown:interferometer/delaunay/alma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay/alma:hpc_a100_fp64` | +| `breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_fp64` | +| `breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64` | +| `breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64_sparse` | +| `breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_fp64` | +| `breakdown:interferometer/mge/alma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/alma:hpc_a100_fp64` | +| `breakdown:interferometer/mge/alma:hpc_a100_fp64_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/mge/alma:hpc_a100_fp64_sparse` | +| `breakdown:interferometer/pixelization/alma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization/alma:hpc_a100_fp64` | +| `breakdown:interferometer/sma/delaunay/sma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/delaunay/sma:hpc_a100_fp64` | +| `breakdown:interferometer/sma/mge/sma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/mge/sma:hpc_a100_fp64` | +| `breakdown:interferometer/sma/pixelization/sma:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/pixelization/sma:hpc_a100_fp64` | +| `breakdown:point_source_source/source_plane/simple:hpc_a100_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:point_source_source/source_plane/simple:hpc_a100_fp64` | + +### lens / comparisons on cpu · backend unknown · float64 + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `runtime:point_source_image/image_plane_solved:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:point_source_image/image_plane_solved:local_cpu_fp64` | +| `runtime:point_source_source/source_plane_solved:local_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:point_source_source/source_plane_solved:local_cpu_fp64` | + +### lens / comparisons on ral_cpu · cpu · float64 + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64` | +| `breakdown:cluster/image_plane:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:cluster/image_plane:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/alma_high/delaunay/alma_high:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/delaunay/alma_high:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/alma_high/delaunay_numba/alma_high:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/delaunay_numba/alma_high:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/alma_high/pixelization/alma_high:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/pixelization/alma_high:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/alma_high/pixelization_numba/alma_high:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/pixelization_numba/alma_high:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/delaunay/alma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay/alma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/delaunay_numba/alma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay_numba/alma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/pixelization/alma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization/alma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/pixelization_numba/alma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization_numba/alma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/sma/delaunay/sma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/delaunay/sma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/sma/delaunay_numba/sma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/delaunay_numba/sma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/sma/pixelization/sma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/pixelization/sma:hpc_ral_cpu_fp64` | +| `breakdown:interferometer/sma/pixelization_numba/sma:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/pixelization_numba/sma:hpc_ral_cpu_fp64` | +| `breakdown:point_source_image/image_plane/simple:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:point_source_image/image_plane/simple:hpc_ral_cpu_fp64` | +| `breakdown:point_source_source/source_plane/simple:hpc_ral_cpu_fp64` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:point_source_source/source_plane/simple:hpc_ral_cpu_fp64` | + +### lens / comparisons on a100 · gpu · mixed + +| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) | Status | Qualified | Reasons | Triage | +|---|---|---|---|---:|---|---|---|---| +| `breakdown:datacube/delaunay/alma_high:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:datacube/delaunay/alma_high:hpc_a100_mp` | +| `breakdown:imaging/delaunay/hst:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay/hst:hpc_a100_mp` | +| `breakdown:imaging/delaunay/hst:hpc_a100_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/delaunay/hst:hpc_a100_mp_sparse` | +| `breakdown:imaging/pixelization/hst:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization/hst:hpc_a100_mp` | +| `breakdown:imaging/pixelization/hst:hpc_a100_mp_sparse` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:imaging/pixelization/hst:hpc_a100_mp_sparse` | +| `breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_mp` | +| `breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_mp` | +| `breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_mp` | +| `breakdown:interferometer/delaunay/alma:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/delaunay/alma:hpc_a100_mp` | +| `breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_mp` | +| `breakdown:interferometer/jvla/mge/jvla:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/mge/jvla:hpc_a100_mp` | +| `breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_mp` | +| `breakdown:interferometer/pixelization/alma:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/pixelization/alma:hpc_a100_mp` | +| `breakdown:interferometer/sma/delaunay/sma:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/delaunay/sma:hpc_a100_mp` | +| `breakdown:interferometer/sma/pixelization/sma:hpc_a100_mp` | runtime-drift-2x-1ms | runtime · single_jit_s | — → — | — | insufficient | no | one release only | `/profiling triage breakdown:interferometer/sma/pixelization/sma:hpc_a100_mp` | diff --git a/pulse/__init__.py b/pulse/__init__.py new file mode 100644 index 0000000..3c7a7d5 --- /dev/null +++ b/pulse/__init__.py @@ -0,0 +1,15 @@ +"""PyAutoPulse: the cross-project profiling dashboard organ. + +The ``_profiling`` project repos run their profiling producers, keep their +results and drift policy, and each one publishes a ``profiling-summary`` file. +This package reads the instance registry (``registry.yaml``), resolves each +instance's repository through the PyAutoMind body map, reads its summary at +one resolved commit, validates the exchange contract, writes an ingest receipt +and builds the board (``dashboard.md`` + ``dashboard.html`` + ``state.json``). +It recomputes no ratio, moves no pin, combines no unmatched timings and judges +nothing: judgment belongs to the Brain's profiling conductor. +""" + +from pathlib import Path + +ORGAN_ROOT = Path(__file__).resolve().parents[1] diff --git a/pulse/board.py b/pulse/board.py new file mode 100644 index 0000000..e5e25ad --- /dev/null +++ b/pulse/board.py @@ -0,0 +1,860 @@ +"""Build the board (``dashboard.md`` + ``dashboard.html``, plus ``badge.json`` and +the ``state.json`` organ-cockpit feed) from the ingested snapshots. + +The first section is one row per registered project: scope, evidence time, +last fetch (with the resolved commit), coverage, and three separate columns +for the three notions the spec keeps apart — **integrity** (transport and +schema: ok / invalid / unavailable / unsupported / cached), **freshness** +(``valid_until``; when the producer declares none, "freshness policy +unspecified" with the evidence's age at fetch, never an invented TTL) and +**qualification** (how many records and comparisons the producer itself marks +qualified). Then one detail section per instance shows the producer's own +``limitations[]`` verbatim, its refused (excluded) rows, and its own +``comparisons[]`` grouped by hardware identity, each with links to its two +records' evidence at the captured commit and a ``/profiling triage `` +manual handoff. Pairs the reader refuses (axis mismatch, changed hardware, +missing endpoint) are listed apart with the reason and no ratio. + +The board never recomputes a ratio, never combines records whose axis or +hardware differs, never ranks cells across projects and never emits a +release verdict. Its output is deterministic: the pages carry no wall-clock +stamp (every time shown comes from a receipt or snapshot) and ``state.json``'s +``updated`` moves only when the feed's content does. +""" + +from __future__ import annotations + +import html +import json +import re +from collections import OrderedDict +from datetime import UTC, datetime +from pathlib import Path + +from pulse import ORGAN_ROOT +from pulse import summary as summary_mod +from pulse.ingest import Snapshot + +PAGES_URL = "https://pyautolabs.github.io/PyAutoPulse/" +REPO_URL = "https://github.com/PyAutoLabs/PyAutoPulse" +STATE_SCHEMA_VERSION = 1 # the organ-cockpit feed contract (PyAutoBrain/board/state_schema.json) +FRESHNESS_DAYS = 90 # presentation only: when an unspecified-policy feed is called out +MARKER = re.compile(r"") + + +# ------------------------------------------------------------- per view --- + + +def _short(sha: str | None) -> str: + return sha[:8] if sha else "—" + + +def _date(stamp: str | None) -> str: + return stamp[:10] if isinstance(stamp, str) else "—" + + +def _days(later: str | None, earlier: str | None) -> int | None: + a, b = summary_mod.parse_utc(later), summary_mod.parse_utc(earlier) + if a is None or b is None: + return None + return max(0, (a - b).days) + + +def records(s: Snapshot) -> list[dict]: + return list((s.doc or {}).get("records") or []) + + +def comparisons(s: Snapshot) -> list[dict]: + return list((s.doc or {}).get("comparisons") or []) + + +def pairs(s: Snapshot) -> list[summary_mod.Pair]: + return summary_mod.pair(s.doc) if s.doc else [] + + +def integrity(s: Snapshot) -> str: + """Transport + schema integrity of the latest read.""" + if s.source == "local": + dirty = {True: "dirty", False: "clean", None: "state unknown"}[s.dirty] + where = f"local checkout {_short(s.commit)} ({dirty})" + return where if not s.failed else f"{s.outcome} · {where}" + if not s.failed: + return "ok" + if s.cached: + return f"cached · latest fetch {s.outcome}" + return s.outcome + + +def evidence(s: Snapshot) -> str: + if not s.doc: + return "—" + ev = s.doc.get("evidence_updated_at") + if ev is None: + return f"unknown ({s.doc.get('evidence_updated_at_reason') or 'no reason given'})" + return _date(ev) + + +def freshness(s: Snapshot, now: str | None = None) -> str: + """Evidence freshness against the producer's own policy, never a global TTL.""" + if not s.doc: + return "—" + ev = s.doc.get("evidence_updated_at") + vu = s.doc.get("valid_until") + if vu is not None: + if now is not None and summary_mod.parse_utc(now) > summary_mod.parse_utc(vu): + return f"stale (valid_until {_date(vu)} passed)" + return f"valid until {_date(vu)}" + if ev is None: + return "freshness policy unspecified · evidence time unknown" + age = _days(s.fetched_at, ev) + at = f" at fetch {_date(s.fetched_at)}" if s.fetched_at else "" + aged = f"age {age} d{at}" if age is not None else "age unknown" + return f"freshness policy unspecified · {aged}" + + +def qualification(s: Snapshot) -> str: + """The producer's own qualification flags, counted, never upgraded.""" + if not s.doc: + return "—" + recs, comps = records(s), comparisons(s) + if not recs: + return "no measurements" + q = summary_mod.qualified_records(s.doc) + cq = sum(1 for c in comps if c.get("qualified") is True) + return f"{q}/{len(recs)} records · {cq}/{len(comps)} comparisons qualified" + + +def coverage(s: Snapshot) -> str: + if not s.doc: + return "—" + if not records(s): + return "no measurements" + cov = s.doc.get("coverage") or {} + obs = cov.get("observed") or {} + parts = [f"{v} {k}" for k, v in obs.items()] + parts.append(f"{len(cov.get('excluded') or [])} excluded") + return " · ".join(parts) + + +def last_fetch(s: Snapshot) -> str: + if s.source == "local": + return f"local read · {_short(s.commit)}" + if s.fetched_at is None and s.attempt_at is None: + return "never" + if s.cached: + return f"{_date(s.fetched_at)} @ {_short(s.commit)} (attempt {_date(s.attempt_at)} failed)" + if s.doc: + return f"{_date(s.fetched_at)} @ {_short(s.commit)}" + return f"attempt {_date(s.attempt_at)} failed" + + +def drifted(s: Snapshot) -> list[summary_mod.Pair]: + return [p for p in pairs(s) if not p.refused and p.comparison.get("status") == "drifted"] + + +def triage_line(p: summary_mod.Pair) -> str: + return f"/profiling triage {p.key}" + + +def receipt_url(s: Snapshot) -> str: + return f"{REPO_URL}/blob/main/receipts/{s.instance.instance}.json" + + +def counts(views) -> list[tuple[str, int]]: + """The head-of-page counts a cockpit strip can read.""" + return [ + ("Projects", len(views)), + ("Records", sum(len(records(s)) for s in views)), + ("Comparisons", sum(len(comparisons(s)) for s in views)), + ("Drifted", sum(len(drifted(s)) for s in views)), + ("Refused pairs", sum(sum(1 for p in pairs(s) if p.refused) for s in views)), + ("Cached", sum(1 for s in views if s.cached)), + ("Failed", sum(1 for s in views if s.failed and not s.cached)), + ] + + +def _grouped(s: Snapshot) -> OrderedDict[str, list[summary_mod.Pair]]: + """Accepted pairs by hardware group, producer order kept (never ranked); + refused pairs last.""" + groups: OrderedDict[str, list] = OrderedDict() + for p in pairs(s): + if not p.refused: + groups.setdefault(p.group, []).append(p) + refused = [p for p in pairs(s) if p.refused] + if refused: + groups["refused"] = refused + return groups + + +def _ratio(p: summary_mod.Pair) -> str: + if p.refused: + return "not shown (refused)" + r = p.comparison.get("ratio") + return "—" if r is None else json.dumps(r) + + +def _endpoint(s: Snapshot, p: summary_mod.Pair, end: str) -> tuple[str, str | None]: + """(label, evidence URL at the captured commit) for one endpoint.""" + ref = p.comparison.get(end) + rec = getattr(p, end) + if ref is None: + return "—", None + if rec is None: + return str(ref), None + ev = rec.get("evidence") or {} + url = s.instance.blob_url(s.commit, ev["path"]) + frag = ev.get("fragment") + return (f"{ref} [{frag}]" if frag else str(ref)), url + + +def marker(s: Snapshot) -> str: + receipt = s.attempt_commit or "none" + shown = s.commit or "none" + return ( + f"" + ) + + +def markers(text: str) -> dict[str, dict]: + """``{instance: {receipt, outcome, shown}}`` as recorded in a dashboard.md.""" + return { + name: {"receipt": receipt, "outcome": outcome, "shown": shown} + for name, receipt, outcome, shown in MARKER.findall(text or "") + } + + +# ------------------------------------------------------------- markdown --- + +LEDE = ( + "The cross-project view of the organism's profiling. Each `_profiling` project repo " + "runs its producers, keeps its results and drift policy, and publishes a " + "`profiling-summary` file. This page reads each file at one resolved commit, validates the " + "exchange contract and shows what the producer says: it recomputes no ratio, combines no " + "timings whose axis or hardware differs, ranks nothing across projects and issues no " + "verdict. Judgment belongs to the Brain's profiling conductor (`/profiling triage`)." +) +NOTIONS = ( + "Three notions are kept apart: **integrity** is whether the file was fetched and meets the " + "contract; **freshness** is the evidence's age against the producer's own `valid_until` " + '(none declared → "freshness policy unspecified"); **qualification** is the producer\'s own ' + "flag on each record and comparison. Healthy transport never makes unknown quality green." +) + + +def _md_escape(text: str) -> str: + return str(text).replace("|", "\\|").replace("\n", " ") + + +def _status_lines(s: Snapshot, now: str | None = None) -> list[str]: + inst = s.instance + out = [] + if s.source == "local": + out.append( + f"**Local read:** `{Path(s.checkout or '?').name}` at `{_short(s.commit)}` " + f"({'dirty' if s.dirty else 'clean' if s.dirty is False else 'state unknown'}) — " + "not a published capture; no receipt written." + ) + out.append("") + if s.cached: + out.append( + f"**Cached:** showing the last good capture (commit `{_short(s.commit)}`, fetched " + f"{s.fetched_at}, evidence {evidence(s)}). The latest fetch ({s.attempt_at}) " + f"was **{s.outcome}**: {'; '.join(s.errors) or 'no error recorded'}." + ) + elif s.failed: + out.append(f"**{s.outcome.capitalize()}:** {'; '.join(s.errors) or 'no error recorded'}.") + if s.doc: + doc = s.doc + pol = doc.get("comparison_policy") or {} + rev = doc.get("producer_revision") + out += [ + f"Project `{doc.get('project')}`, scope `{doc.get('scope')}`, read from " + f"[{inst.github}]({inst.github_url}) `{inst.summary_path}` at " + f"[`{_short(s.commit)}`]({inst.tree_url(s.commit)}); producer revision " + f"`{_short(rev)}`; generated {doc.get('generated_at')}; comparison policy " + f"`{pol.get('id')}`. [Project dashboard]({inst.dashboard_url}) · " + f"[receipt]({receipt_url(s)}).", + "", + f"- **Integrity:** {integrity(s)}", + f"- **Freshness:** {freshness(s, now)} (evidence {evidence(s)})", + f"- **Qualification:** {qualification(s)}", + ] + return out + + +def _md_detail(s: Snapshot, now: str | None = None) -> list[str]: + inst = s.instance + out = ["", f"## {inst.instance}", "", marker(s), ""] + out += _status_lines(s, now) + if not s.doc: + return out + if not records(s): + out += [ + "", + "**No measurements.** The producer published a valid, empty feed — this is not " + '"all measurements passed".', + ] + lims = s.doc.get("limitations") or [] + out += ["", f"### {inst.instance} / limitations", ""] + out += [f"- {_md_escape(x)}" for x in lims] or ["- none declared"] + excluded = (s.doc.get("coverage") or {}).get("excluded") or [] + if excluded: + out += ["", f"### {inst.instance} / excluded by the producer", ""] + for x in excluded: + ev = x.get("evidence") or {} + out.append( + f"- `{x.get('id')}`: {_md_escape(x.get('reason'))} " + f"([evidence]({inst.blob_url(s.commit, ev.get('path'))}))" + ) + for group, items in _grouped(s).items(): + title = ( + "refused by the reader (never combined)" + if group == "refused" + else f"comparisons on {group}" + ) + out += [ + "", + f"### {inst.instance} / {title}", + "", + "| Comparison | Policy | Axis · metric | Baseline → candidate | Ratio (producer) " + "| Status | Qualified | Reasons | Triage |", + "|---|---|---|---|---:|---|---|---|---|", + ] + for p in items: + c = p.comparison + ends = [] + for end in ("baseline", "candidate"): + label, url = _endpoint(s, p, end) + ends.append(f"[{label}]({url})" if url else label) + reasons = "; ".join(list(c.get("reasons") or []) + p.refused) or "—" + out.append( + f"| `{_md_escape(p.key)}` | {c.get('policy')} | {c.get('axis')} · " + f"{c.get('metric')} | {' → '.join(ends)} | {_ratio(p)} | {c.get('status')} | " + f"{'yes' if c.get('qualified') else 'no'} | {_md_escape(reasons)} | " + f"`{triage_line(p)}` |" + ) + return out + + +def render_markdown(views, now: str | None = None) -> str: + now = now or _utc_now() + out = [ + "# PyAutoPulse — profiling dashboard", + "", + "", + "", + LEDE, + f"Live page: [{PAGES_URL}]({PAGES_URL}).", + "", + "| Where | Count |", + "|-------|------:|", + *[f"| [{label}](#projects) | {n} |" for label, n in counts(views)], + "", + "## Projects", + "", + "| Project | Scope | Evidence | Last fetch | Coverage | Integrity | Freshness " + "| Qualification | Links |", + "|---|---|---|---|---|---|---|---|---|", + ] + for s in views: + inst = s.instance + scope = (s.doc or {}).get("scope") or "—" + out.append( + f"| [{inst.instance}](#{inst.instance}) ({inst.repo}) | {scope} | {evidence(s)} | " + f"{last_fetch(s)} | {coverage(s)} | {integrity(s)} | {freshness(s, now)} | " + f"{qualification(s)} | [dashboard]({inst.dashboard_url}) · " + f"[repo]({inst.github_url}) · [receipt]({receipt_url(s)}) |" + ) + out += ["", NOTIONS] + for s in views: + out += _md_detail(s, now) + return "\n".join(out).rstrip("\n") + "\n" + + +# ----------------------------------------------------------------- html --- + +CSS = """ +:root{--bg:#ffffff;--fg:#1f2328;--muted:#59636e;--card:#f6f8fa;--line:#d1d9e0; +--accent:#0b7a4b;--hero1:#062b1c;--hero2:#000000;--glow:#2ee88f;--ok:#1a7f37;--warn:#9a6700; +--bad:#cf222e} +@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#0d1117;--fg:#e6edf3; +--muted:#9198a1;--card:#151b23;--line:#3d444d;--accent:#34d399;--ok:#3fb950;--warn:#d29922; +--bad:#f85149}} +:root[data-theme="dark"]{--bg:#0d1117;--fg:#e6edf3;--muted:#9198a1;--card:#151b23; +--line:#3d444d;--accent:#34d399;--ok:#3fb950;--warn:#d29922;--bad:#f85149} +*{box-sizing:border-box} +body{margin:0;background:var(--bg);color:var(--fg); +font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif} +main{max-width:1200px;margin:0 auto;padding:0 16px 48px} +.hero{background:radial-gradient(circle at 30% 20%,var(--hero1),var(--hero2));color:#fff; +padding:28px 16px 22px;text-align:center} +.hero h1{margin:0;font-size:28px;letter-spacing:.5px}.hero h1 span{color:var(--glow)} +.hero p{margin:6px 0 0;color:#bfe9d3;font-size:13px;letter-spacing:2px;text-transform:uppercase} +h2,h3{color:var(--accent)}h2{border-bottom:1px solid var(--line);padding-bottom:4px;margin-top:32px} +a{color:var(--accent)} +.lede{color:var(--muted)} +.tablewrap{overflow-x:auto} +table{border-collapse:collapse;width:100%;font-size:14px} +th,td{border-bottom:1px solid var(--line);padding:6px 8px;text-align:left;vertical-align:top} +td.num{text-align:right;white-space:nowrap} +.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}.muted{color:var(--muted)} +.notions{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:8px;margin:8px 0} +.notions div{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:8px 12px} +.notions b{display:block;font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:1px} +.stats{display:flex;flex-wrap:wrap;gap:12px;margin:16px 0} +.stats div{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:8px 14px} +.stats b{display:block;font-size:20px;color:var(--accent)}.stats span{font-size:12px;color:var(--muted)} +button[data-copy]{font:12px ui-monospace,SFMono-Regular,Menlo,monospace;text-align:left; +background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:6px; +padding:3px 6px;cursor:pointer;word-break:break-all} +button.copied{border-color:var(--ok)} +code{color:var(--accent);word-break:break-all} +""" + +JS = """ +document.querySelectorAll('button[data-copy]').forEach(function(b){ + b.addEventListener('click',function(){ + var t=b.getAttribute('data-copy'); + var done=function(){b.classList.add('copied');setTimeout(function(){b.classList.remove('copied')},1200)}; + if(navigator.clipboard){navigator.clipboard.writeText(t).then(done,function(){})} + }); +}); +document.querySelectorAll('[data-age-from]').forEach(function(el){ + var t=Date.parse(el.getAttribute('data-age-from')); + if(!isNaN(t)){el.textContent=' · '+Math.max(0,Math.floor((Date.now()-t)/864e5))+' d today';} +}); +""" + + +def _e(value) -> str: + return html.escape(str(value), quote=True) + + +def _integrity_class(s: Snapshot) -> str: + if not s.failed: + return "ok" if s.source == "remote" else "warn" + return "warn" if s.cached else "bad" + + +def _html_notions(s: Snapshot, now: str | None = None) -> str: + ev = (s.doc or {}).get("evidence_updated_at") + live = f"" if ev else "" + return ( + "
" + f"
Integrity{_e(integrity(s))}
" + f"
Freshness{_e(freshness(s, now))} (evidence {_e(evidence(s))}){live}
" + f"
Qualification{_e(qualification(s))}
" + "
" + ) + + +def _html_detail(s: Snapshot, now: str | None = None) -> str: + inst = s.instance + parts = [f"

{_e(inst.instance)} · {_e(inst.repo)}

"] + if s.source == "local": + parts.append( + f"

Local read of {_e(Path(s.checkout or '?').name)} at " + f"{_e(_short(s.commit))} " + f"({'dirty' if s.dirty else 'clean' if s.dirty is False else 'state unknown'}): " + "not a published capture; no receipt written.

" + ) + if s.cached: + parts.append( + f"

Cached: last good capture at " + f"{_e(_short(s.commit))}, fetched {_e(s.fetched_at)}, evidence " + f"{_e(evidence(s))}. Latest fetch ({_e(s.attempt_at)}) was {_e(s.outcome)}: " + f"{_e('; '.join(s.errors) or 'no error recorded')}.

" + ) + elif s.failed: + parts.append( + f"

{_e(s.outcome)}: {_e('; '.join(s.errors) or 'no error')}

" + ) + if not s.doc: + return "".join(parts) + doc = s.doc + pol = doc.get("comparison_policy") or {} + parts.append( + f"

Project {_e(doc.get('project'))}, scope " + f"{_e(doc.get('scope'))}, read from " + f"{_e(inst.github)} {_e(inst.summary_path)} at " + f"{_e(_short(s.commit))}; " + f"producer revision {_e(_short(doc.get('producer_revision')))}; generated " + f"{_e(doc.get('generated_at'))}; policy {_e(pol.get('id'))}. " + f"Project dashboard · " + f"receipt.

" + ) + parts.append(_html_notions(s, now)) + if not records(s): + parts.append( + "

No measurements. A valid, empty feed — not " + "“all measurements passed”.

" + ) + lims = doc.get("limitations") or [] + parts.append("

Limitations (the producer's own)

    ") + parts += [f"
  • {_e(x)}
  • " for x in lims] or ["
  • none declared
  • "] + parts.append("
") + excluded = (doc.get("coverage") or {}).get("excluded") or [] + if excluded: + parts.append("

Excluded by the producer

    ") + for x in excluded: + ev = x.get("evidence") or {} + parts.append( + f"
  • {_e(x.get('id'))}: {_e(x.get('reason'))} " + f"(evidence)
  • " + ) + parts.append("
") + for group, items in _grouped(s).items(): + title = ( + "Refused by the reader (never combined)" + if group == "refused" + else f"Comparisons on {group}" + ) + rows = [] + for p in items: + c = p.comparison + ends = [] + for end in ("baseline", "candidate"): + label, url = _endpoint(s, p, end) + ends.append(f"{_e(label)}" if url else _e(label)) + reasons = "; ".join(list(c.get("reasons") or []) + p.refused) or "—" + line = triage_line(p) + rows.append( + f"{_e(p.key)}{_e(c.get('policy'))}" + f"{_e(c.get('axis'))} · {_e(c.get('metric'))}{' → '.join(ends)}" + f"{_e(_ratio(p))}{_e(c.get('status'))}" + f"{'yes' if c.get('qualified') else 'no'}{_e(reasons)}" + f"" + ) + parts.append( + f"

{_e(title)}

" + "" + "" + f"{''.join(rows)}
ComparisonPolicyAxis · metricBaseline → candidateRatio (producer)StatusQualifiedReasonsTriage
" + ) + return "".join(parts) + + +def render_html(views, now: str | None = None) -> str: + now = now or _utc_now() + rows = [] + for s in views: + inst = s.instance + rows.append( + f"{_e(inst.instance)} " + f"{_e(inst.repo)}" + f"{_e((s.doc or {}).get('scope') or '—')}{_e(evidence(s))}" + f"{_e(last_fetch(s))}{_e(coverage(s))}" + f"{_e(integrity(s))}" + f"{_e(freshness(s, now))}{_e(qualification(s))}" + f"dashboard · " + f"repo · " + f"receipt" + ) + tiles = "".join(f"
{n}{_e(label)}
" for label, n in counts(views)) + lede = _e(LEDE).replace("`/profiling triage`", "/profiling triage") + lede = re.sub(r"`(.+?)`", r"\1", lede) + notions = re.sub(r"\*\*(.+?)\*\*", r"\1", _e(NOTIONS)) + notions = re.sub(r"`(.+?)`", r"\1", notions) + return ( + "\n" + "" + "PyAutoPulse dashboard" + "" + f"" + "

PyAutoPulse

" + "

Measure. Trace. Compare.

" + f"

{lede}

" + f"
{tiles}
" + "

Projects

" + "
" + "" + "" + f"{''.join(rows)}
ProjectScopeEvidenceLast fetchCoverageIntegrityFreshnessQualificationLinks
" + f"

{notions}

" + f"{''.join(_html_detail(s, now) for s in views)}
\n" + ) + + +# ---------------------------------------------------------- badge, state --- + + +def _utc_now() -> str: + return datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ") + + +def headline(views) -> str: + n = len(views) + recs = sum(len(records(s)) for s in views) + cached = sum(1 for s in views if s.cached) + failed = sum(1 for s in views if s.failed and not s.cached) + text = f"{n} project{'' if n == 1 else 's'} · {recs} records · {cached} cached" + if failed: + text += f" · {failed} failed" + return text + + +def _one_line(text: str, limit: int = 300) -> str: + text = " ".join(str(text).split()) + return text if len(text) <= limit else text[: limit - 1] + "…" + + +def _instance_items(s: Snapshot, now: str) -> tuple[list, list, list]: + inst = s.instance + key = inst.instance + red, yellow, info = [], [], [] + fetch_action = { + "id": "fetch", + "label": "Re-fetch this instance", + "kind": "command", + "target": f"bin/pyauto-pulse fetch --instance {key}", + "safety": "read_only", + } + open_action = { + "id": "open", + "label": "Open the project dashboard", + "kind": "link", + "target": inst.dashboard_url, + "safety": "read_only", + } + if s.failed: + why = _one_line("; ".join(s.errors) or "no error recorded", 200) + if s.cached and s.outcome == "unavailable": + yellow.append( + { + "id": f"pulse:{key}:cached", + "severity": "yellow", + "state": "stale", + "text": _one_line( + f"{key}: fetch unavailable; showing cached capture " + f"{_short(s.commit)} from {s.fetched_at}" + ), + "reason": why, + "url": receipt_url(s), + "prompt": None, + "actions": [fetch_action, open_action], + } + ) + else: + tail = f"; showing cached capture {_short(s.commit)}" if s.cached else "" + red.append( + { + "id": f"pulse:{key}:{s.outcome}", + "severity": "red", + "state": "failed", + "text": _one_line(f"{key}: summary {s.outcome}{tail}"), + "reason": why, + "url": receipt_url(s), + "prompt": None, + "actions": [fetch_action, open_action], + } + ) + if not s.doc: + return red, yellow, info + doc = s.doc + ev, vu = doc.get("evidence_updated_at"), doc.get("valid_until") + if vu is not None and summary_mod.parse_utc(now) > summary_mod.parse_utc(vu): + yellow.append( + { + "id": f"pulse:{key}:stale", + "severity": "yellow", + "state": "stale", + "text": f"{key}: evidence stale (valid_until {_date(vu)} passed)", + "url": inst.dashboard_url, + "prompt": None, + "actions": [open_action], + } + ) + elif vu is None and ev is not None and (_days(now, ev) or 0) > FRESHNESS_DAYS: + yellow.append( + { + "id": f"pulse:{key}:aged", + "severity": "yellow", + "state": "stale", + "text": ( + f"{key}: evidence from {_date(ev)} is older than {FRESHNESS_DAYS} d; " + "freshness policy unspecified" + ), + "url": inst.dashboard_url, + "prompt": None, + "actions": [open_action], + } + ) + recs = records(s) + if not recs: + yellow.append( + { + "id": f"pulse:{key}:empty", + "severity": "yellow", + "state": "unknown", + "text": f"{key}: no measurements (a valid, empty feed)", + "url": inst.dashboard_url, + "prompt": None, + "actions": [open_action], + } + ) + else: + unq = len(recs) - summary_mod.qualified_records(doc) + if unq: + yellow.append( + { + "id": f"pulse:{key}:unqualified", + "severity": "yellow", + "state": "unknown", + "text": ( + f"{key}: {unq} of {len(recs)} records unqualified " + "(producer provenance flags)" + ), + "url": inst.dashboard_url, + "prompt": None, + "actions": [open_action], + } + ) + for p in drifted(s): + c = p.comparison + line = triage_line(p) + actions = [ + { + "id": "triage", + "label": "Hand off to profiling triage", + "kind": "prompt", + "target": line, + "safety": "scientific_judgement", + } + ] + if p.candidate is not None: + actions.append( + { + "id": "evidence", + "label": "Open the candidate's evidence", + "kind": "link", + "target": inst.blob_url(s.commit, p.candidate["evidence"]["path"]), + "safety": "read_only", + } + ) + item = { + "id": f"pulse:{key}:drift:{p.key}", + "severity": "yellow" if c.get("qualified") else "info", + "state": "action_required" if c.get("qualified") else "unknown", + "text": _one_line( + f"{key}: {p.key} drifted (producer ratio {c.get('ratio')}, " + f"{'qualified' if c.get('qualified') else 'unqualified: contextual flag'})" + ), + "reason": _one_line( + f"{c.get('policy')} at {_short(s.commit)}: " + + ("; ".join(c.get("reasons") or []) or "no reasons given"), + 200, + ), + "url": inst.dashboard_url, + "prompt": line, + "actions": actions, + "recommended_action_id": "triage", + } + (yellow if c.get("qualified") else info).append(item) + if s.source == "local": + info.append( + { + "id": f"pulse:{key}:local", + "severity": "info", + "text": ( + f"{key}: rendered from a local checkout {_short(s.commit)} " + f"({'dirty' if s.dirty else 'clean' if s.dirty is False else 'state unknown'})" + ), + "url": None, + "prompt": None, + } + ) + lims = doc.get("limitations") or [] + info.append( + { + "id": f"pulse:{key}:census", + "severity": "info", + "text": ( + f"{key}: {len(recs)} records · {len(comparisons(s))} comparisons · " + f"{len(lims)} limitations · {summary_mod.qualified_records(doc)} qualified" + ), + "url": inst.dashboard_url, + "prompt": None, + } + ) + return red, yellow, info + + +def render_state(views, updated: str | None = None, now: str | None = None) -> dict: + """The organ-cockpit feed (state.json, contract v1 in PyAutoBrain/board). + + status: red when an instance's latest read is invalid or unsupported, or + unavailable with no cached capture; yellow when one is cached, stale + against its own ``valid_until``, older than ``FRESHNESS_DAYS`` without a + policy, empty, carries unqualified records, or has a qualified drift + candidate; else green. Info rows (unqualified drift as a contextual flag, + the census line) never move the status. This summarises the organ's own + monitoring scope, never release readiness. + """ + now = now or _utc_now() + red, yellow, info = [], [], [] + for s in views: + r, y, i = _instance_items(s, now) + red, yellow, info = red + r, yellow + y, info + i + status = "red" if red else "yellow" if yellow else "green" + return { + "schema_version": STATE_SCHEMA_VERSION, + "organ": "pulse", + "repo": "PyAutoPulse", + "status": status, + "headline": headline(views), + "updated": updated or _utc_now(), + "pages_url": PAGES_URL, + "items": red + yellow + info, + } + + +def render_badge(views, state: dict | None = None) -> dict: + """The one-line headline (shields.io endpoint shape) other boards read.""" + state = state or render_state(views, updated="1970-01-01T00:00:00Z") + color = {"red": "red", "yellow": "yellow", "green": "brightgreen"}[state["status"]] + return {"schemaVersion": 1, "label": "pulse", "message": state["headline"], "color": color} + + +# --------------------------------------------------------------- output --- + + +def _carried_updated(path: Path, state: dict) -> str | None: + """The committed state.json's ``updated`` when nothing else changed. + + Keeps the render deterministic (a re-render on unchanged inputs changes no + file, so the nightly refresh commits nothing): ``updated`` moves only when + the feed's content does. + """ + try: + prior = json.loads(path.read_text()) + except (OSError, ValueError): + return None + if not isinstance(prior, dict) or not isinstance(prior.get("updated"), str): + return None + same = {k: v for k, v in prior.items() if k != "updated"} == { + k: v for k, v in state.items() if k != "updated" + } + return prior["updated"] if same else None + + +def write( + views, out_dir: Path = ORGAN_ROOT, updated: str | None = None, now: str | None = None +) -> list[Path]: + out_dir = Path(out_dir) + md, page, badge, feed = ( + out_dir / "dashboard.md", + out_dir / "dashboard.html", + out_dir / "badge.json", + out_dir / "state.json", + ) + md.write_text(render_markdown(views, now)) + page.write_text(render_html(views, now)) + state = render_state(views, updated, now) + if updated is None: + state["updated"] = _carried_updated(feed, state) or state["updated"] + badge.write_text(json.dumps(render_badge(views, state), indent=2) + "\n") + feed.write_text(json.dumps(state, indent=2, ensure_ascii=False) + "\n") + return [md, page, badge, feed] diff --git a/pulse/cli.py b/pulse/cli.py new file mode 100644 index 0000000..6ba6738 --- /dev/null +++ b/pulse/cli.py @@ -0,0 +1,293 @@ +"""``pyauto-pulse``: the organ's command line (check, board, census, fetch).""" + +from __future__ import annotations + +import argparse +import importlib.util +import json +import os +import sys +from pathlib import Path + +from pulse import ORGAN_ROOT, board, ingest, registry +from pulse import summary as summary_mod + + +def _sources(values, instances) -> dict[str, Path]: + """Parse ``--from`` values: ``=``, or a bare ````. + + A bare path is matched to the instance whose repo name is the path's + basename, or to the only instance when the registry has just one. + """ + names = {i.instance for i in instances} + out = {} + for value in values or []: + name, sep, path = value.partition("=") + if sep and name in names: + out[name] = Path(path).expanduser() + continue + path = Path(value).expanduser() + base = path.resolve().name if path.is_dir() else None + match = [i.instance for i in instances if i.repo == base] + if not match and len(instances) == 1: + match = [instances[0].instance] + if len(match) != 1: + raise SystemExit(f"pyauto-pulse: cannot tell which instance --from {value} is for") + out[match[0]] = path + return out + + +def _load(args): + instances = registry.load(args.registry, mind=getattr(args, "mind", None)) + return instances, _sources(getattr(args, "sources", None), instances) + + +def _ingest_all(args, instances, sources) -> list[ingest.Snapshot]: + return [ + ingest.ingest( + inst, + args.out, + offline=getattr(args, "offline", False), + local_path=sources.get(inst.instance), + ) + for inst in instances + ] + + +def _say(s: ingest.Snapshot) -> str: + key = s.instance.instance + if s.doc: + line = ( + f"{key}: {board.integrity(s)}; {len(board.records(s))} records at " + f"{(s.commit or 'unknown')[:8]}; {board.freshness(s)}; {board.qualification(s)}" + ) + else: + line = f"{key}: {board.integrity(s)}" + if s.failed: + line += f" — {'; '.join(s.errors)}" + return line + + +def cmd_board(args) -> int: + instances, sources = _load(args) + views = _ingest_all(args, instances, sources) + for path in board.write(views, args.out): + print(f"wrote {path}") + for s in views: + print(_say(s), file=sys.stderr if s.failed else sys.stdout) + return 0 + + +def cmd_fetch(args) -> int: + instances = registry.load(args.registry, mind=args.mind) + chosen = [registry.get(instances, args.instance)] if args.instance else instances + rc = 0 + for inst in chosen: + s = ingest.ingest(inst, args.out) + receipt = ingest.read_receipt(args.out, inst.instance) or {} + print( + f"{inst.instance}: {receipt.get('outcome')} at " + f"{(receipt.get('resolved_commit') or 'unresolved')[:12]} " + f"(receipt {ingest.receipt_path(args.out, inst.instance)})" + ) + if s.failed: + print(f" {'; '.join(s.errors)}", file=sys.stderr) + rc = 1 + return rc + + +def cmd_census(args) -> int: + instances, sources = _load(args) + for s in _ingest_all(argparse.Namespace(out=args.out, offline=True), instances, sources): + key = s.instance.instance + if not s.doc: + print(f"{key}: no capture ({board.integrity(s)})") + continue + doc = s.doc + print( + f"{key}: {len(board.records(s))} records · {len(board.comparisons(s))} comparisons · " + f"{len(doc.get('limitations') or [])} limitations · " + f"{summary_mod.qualified_records(doc)} qualified · {board.integrity(s)} · " + f"{(s.commit or 'unknown')[:8]}" + ) + return 0 + + +def _state_validator(): + """The Brain's cockpit-feed validator (board/_state.py), or None. + + Looked for at $PYAUTO_BRAIN, then beside this organ (flat or grouped + ``organs/`` layouts both put PyAutoBrain next to PyAutoPulse). + """ + candidates = [] + if os.environ.get("PYAUTO_BRAIN"): + candidates.append(Path(os.environ["PYAUTO_BRAIN"]).expanduser()) + candidates.append(ORGAN_ROOT.parent / "PyAutoBrain") + for root in candidates: + path = root / "board" / "_state.py" + if path.is_file(): + spec = importlib.util.spec_from_file_location("_brain_state", path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + return None + + +def _check_state(path: Path) -> list[str]: + """state.json exists, parses, and (when the Brain is here) meets contract v1.""" + if not path.is_file(): + print("FAIL state: state.json missing — run `pyauto-pulse board`") + return ["state.json missing"] + try: + state = json.loads(path.read_text()) + except ValueError as exc: + print(f"FAIL state: state.json unreadable ({exc})") + return [f"state.json unreadable: {exc}"] + validator = _state_validator() + if validator is None: + print("skip state: no PyAutoBrain here to validate state.json (set PYAUTO_BRAIN)") + return [] + errors = validator.validate_state(state) + if errors: + print(f"FAIL state: {'; '.join(errors)}") + return [f"state.json: {e}" for e in errors] + print(f"ok state: valid against the Brain contract ({state['status']}, {state['headline']})") + return [] + + +def cmd_check(args) -> int: + problems = [] + try: + body_map = registry.load_body_map(args.mind) + print(f"ok body map: {registry.body_map_path(args.mind)}") + instances = registry.load(args.registry, body_map=body_map) + except registry.RegistryError as exc: + print(f"FAIL registry: {exc}") + return 1 + print( + f"ok registry: {len(instances)} instance(s) " + f"({', '.join(f'{i.instance}→{i.github}' for i in instances)})" + ) + sources = _sources(args.sources, instances) + views = _ingest_all(args, instances, sources) + mode = "committed receipts + snapshots" if args.offline else "fetched at one resolved commit" + for s in views: + key = s.instance.instance + if s.failed: + problems.append(f"{key}: {s.outcome}: {'; '.join(s.errors)}") + print(f"FAIL {key}: {s.outcome}: {'; '.join(s.errors)}") + continue + if s.source == "remote": + receipt = ingest.read_receipt(args.out, key) + if not receipt or receipt.get("resolved_commit") != s.commit: + problems.append(f"{key}: receipt does not record the snapshot commit") + print(f"FAIL {key}: receipt does not record the snapshot commit") + continue + # The committed snapshot must still validate under this reader. + outcome, errors = summary_mod.classify( + s.doc, (s.instance.schema_name, s.instance.schema_version) + ) + if outcome != "ok": + problems.append(f"{key}: snapshot {outcome}: {'; '.join(errors)}") + print(f"FAIL {key}: snapshot {outcome}: {'; '.join(errors[:5])}") + continue + print( + f"ok {key}: {s.doc['schema']}@{s.doc['version']} valid, " + f"{len(board.records(s))} records, {len(board.comparisons(s))} comparisons at " + f"{(s.commit or 'unknown')[:12]} ({mode if s.source == 'remote' else 'local read'})" + ) + out = Path(args.out) + md, page = out / "dashboard.md", out / "dashboard.html" + if not md.is_file() or not page.is_file(): + problems.append("dashboard.md / dashboard.html missing") + print("FAIL dashboard: dashboard.md / dashboard.html missing — run `pyauto-pulse board`") + else: + recorded = board.markers(md.read_text()) + names = {i.instance for i in instances} + stale = sorted( + s.instance.instance + for s in views + if s.source == "remote" + and recorded.get(s.instance.instance) + != { + "receipt": s.attempt_commit or "none", + "outcome": s.outcome, + "shown": s.commit or "none", + } + ) + extra = sorted(set(recorded) - names) + if stale or extra: + problems.append(f"dashboard stale: {stale + extra}") + print( + f"FAIL dashboard: stale for {', '.join(stale + extra)} — run `pyauto-pulse board`" + ) + else: + print("ok dashboard: current with every receipt") + problems += _check_state(out / "state.json") + print("check: " + ("FAIL" if problems else "OK")) + return 1 if problems else 0 + + +def main(argv=None) -> int: + parser = argparse.ArgumentParser( + prog="pyauto-pulse", + description="PyAutoPulse: the cross-project profiling dashboard organ.", + ) + parser.add_argument("--registry", default=str(registry.REGISTRY_PATH), help=argparse.SUPPRESS) + sub = parser.add_subparsers(dest="cmd", required=True) + + def common(p, reading=True): + p.add_argument( + "--mind", + metavar="PATH", + help="the PyAutoMind checkout whose repos.yaml resolves each instance's repo " + "(default: $PYAUTO_MIND, else $PYAUTO_ROOT or beside this organ)", + ) + p.add_argument("--out", default=str(ORGAN_ROOT), help=argparse.SUPPRESS) + if reading: + p.add_argument( + "--offline", + action="store_true", + help="use the committed receipts + snapshots, never the network", + ) + p.add_argument( + "--from", + dest="sources", + action="append", + metavar="[INSTANCE=]PATH", + help="read an instance's summary from this local checkout or file " + "(labelled as a local read; writes no receipt)", + ) + + p = sub.add_parser( + "board", help="ingest, then render dashboard.md + dashboard.html + badge.json + state.json" + ) + common(p) + p.set_defaults(func=cmd_board) + p = sub.add_parser( + "check", + help="registry + body map valid, every summary ingests and validates, receipt written, " + "dashboard current, state.json valid", + ) + common(p) + p.set_defaults(func=cmd_check) + p = sub.add_parser( + "census", help="one line per instance from the committed snapshots (no network)" + ) + common(p, reading=False) + p.set_defaults(func=cmd_census, sources=None) + p = sub.add_parser("fetch", help="ingest and write receipts only (no render)") + common(p, reading=False) + p.add_argument("--instance", metavar="K", help="only this instance") + p.set_defaults(func=cmd_fetch) + + args = parser.parse_args(argv) + try: + return args.func(args) + except registry.RegistryError as exc: + print(f"pyauto-pulse: {exc}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/pulse/ingest.py b/pulse/ingest.py new file mode 100644 index 0000000..776e096 --- /dev/null +++ b/pulse/ingest.py @@ -0,0 +1,300 @@ +"""Ingest one instance's summary at one resolved commit, with a receipt. + +An online ingest resolves the instance's branch to **one commit** through the +GitHub API and reads ``summary_path`` at that SHA from +``raw.githubusercontent.com`` — never at a moving branch name, so every value +the board shows traces to a captured commit. Each attempt writes a receipt +(``receipts/.json``: resolved commit, fetch time, outcome, errors). +A good read also writes the last-good snapshot (``snapshots/.json``: +the summary plus the commit and time it was captured). A failed read keeps +that snapshot and the board shows it labelled **cached**, with its original +evidence and fetch times and the new error: nothing re-ages it. + +Receipts and snapshots are written only when their content changes (the +``fetched_at`` of an unchanged outcome at the same commit is carried), so a +nightly refresh against an unchanged project commits nothing. A local +``--from`` read reports the checkout's revision and dirty state, is labelled +"local checkout", and writes no receipt or snapshot: it cannot masquerade as +a published capture. +""" + +from __future__ import annotations + +import json +import os +import re +import subprocess +import urllib.error +import urllib.request +from dataclasses import dataclass, field +from datetime import UTC, datetime +from pathlib import Path + +from pulse import ORGAN_ROOT +from pulse import summary as summary_mod +from pulse.registry import Instance + +API_COMMIT = "https://api.github.com/repos/{github}/commits/{branch}" +RAW_FILE = "https://raw.githubusercontent.com/{github}/{sha}/{path}" +TIMEOUT = 20 +USER_AGENT = "PyAutoPulse-ingest (+https://github.com/PyAutoLabs/PyAutoPulse)" +OUTCOMES = ("ok", "invalid", "unavailable", "unsupported") +_SHA = re.compile(r"^[0-9a-f]{40}$") + + +class FetchError(Exception): + """A transport failure: the API or the raw file could not be read.""" + + +def utc_now() -> str: + return datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ") + + +# --------------------------------------------------------------- network --- + + +def _get(url: str, accept: str | None = None) -> bytes: + headers = {"User-Agent": USER_AGENT} + if accept: + headers["Accept"] = accept + token = os.environ.get("GH_TOKEN") + if token and url.startswith("https://api.github.com/"): + headers["Authorization"] = f"Bearer {token}" + request = urllib.request.Request(url, headers=headers) + try: + with urllib.request.urlopen(request, timeout=TIMEOUT) as response: + return response.read() + except (urllib.error.URLError, OSError, ValueError) as exc: + raise FetchError(f"GET {url}: {exc}") from exc + + +def resolve_commit(github: str, branch: str = "main") -> str: + """The one commit ``branch`` points at now (40-hex SHA).""" + body = _get(API_COMMIT.format(github=github, branch=branch), "application/vnd.github+json") + try: + sha = json.loads(body)["sha"] + except (ValueError, KeyError, TypeError) as exc: + raise FetchError(f"{github}@{branch}: unreadable commit response ({exc})") from exc + if not (isinstance(sha, str) and _SHA.match(sha)): + raise FetchError(f"{github}@{branch}: commit response has no 40-hex sha") + return sha + + +def fetch_at(github: str, sha: str, path: str) -> bytes: + """``path`` exactly as it is at commit ``sha``.""" + return _get(RAW_FILE.format(github=github, sha=sha, path=path)) + + +# -------------------------------------------------------------- snapshot --- + + +@dataclass +class Snapshot: + """What the board shows for one instance. + + ``outcome``/``errors``/``attempt_*`` describe the latest attempt; + ``doc``/``commit``/``fetched_at`` describe the summary shown, which is the + last good capture when the latest attempt failed (``cached``). + """ + + instance: Instance + outcome: str + source: str # remote | local | none + doc: dict | None = None + commit: str | None = None + fetched_at: str | None = None + errors: list[str] = field(default_factory=list) + cached: bool = False + attempt_commit: str | None = None + attempt_at: str | None = None + dirty: bool | None = None + checkout: str | None = None + + @property + def failed(self) -> bool: + return self.outcome != "ok" + + +def receipt_path(out_dir: Path, name: str) -> Path: + return Path(out_dir) / "receipts" / f"{name}.json" + + +def snapshot_path(out_dir: Path, name: str) -> Path: + return Path(out_dir) / "snapshots" / f"{name}.json" + + +def _read_json(path: Path) -> dict | None: + try: + doc = json.loads(path.read_text()) + except (OSError, ValueError): + return None + return doc if isinstance(doc, dict) else None + + +def _write_json(path: Path, doc: dict, indent: int = 2) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + tmp = path.with_name(path.name + ".tmp") + tmp.write_text(json.dumps(doc, indent=indent, ensure_ascii=False) + "\n") + tmp.replace(path) + + +def read_receipt(out_dir: Path, name: str) -> dict | None: + return _read_json(receipt_path(out_dir, name)) + + +def read_snapshot(out_dir: Path, name: str) -> dict | None: + snap = _read_json(snapshot_path(out_dir, name)) + return snap if snap and isinstance(snap.get("summary"), dict) else None + + +def _carry(path: Path, doc: dict, keys=("fetched_at",)) -> bool: + """Write ``doc`` unless the file already holds it apart from ``keys``. + + Returns True when written. Carrying keeps re-ingests of an unchanged + outcome at an unchanged commit from rewriting (and re-aging) the file. + """ + prior = _read_json(path) + if prior is not None: + strip = lambda d: {k: v for k, v in d.items() if k not in keys} # noqa: E731 + if strip(prior) == strip(doc): + return False + _write_json(path, doc) + return True + + +# ---------------------------------------------------------------- ingest --- + + +def _from_files(inst: Instance, out_dir: Path) -> Snapshot: + """The committed receipt + last-good snapshot, read with no network.""" + receipt = read_receipt(out_dir, inst.instance) + snap = read_snapshot(out_dir, inst.instance) + if receipt is None: + view = Snapshot(inst, "unavailable", "none", errors=["no receipt yet (never fetched)"]) + else: + view = Snapshot( + inst, + receipt.get("outcome") if receipt.get("outcome") in OUTCOMES else "invalid", + "remote", + errors=[str(e) for e in receipt.get("errors") or []], + attempt_commit=receipt.get("resolved_commit"), + attempt_at=receipt.get("fetched_at"), + ) + if snap is not None: + view.doc = snap["summary"] + view.commit = snap.get("commit") + view.fetched_at = snap.get("fetched_at") + view.source = "remote" + view.cached = view.failed + return view + + +def ingest( + inst: Instance, + out_dir: Path = ORGAN_ROOT, + *, + offline: bool = False, + local_path: Path | str | None = None, + now: str | None = None, +) -> Snapshot: + """Read one instance and return what the board shows for it. + + ``offline``: the committed receipt + snapshot only (no network, no + write). ``local_path``: a local checkout (or the summary file itself), + labelled as such, writing nothing. Otherwise: resolve, fetch, validate, + write the receipt (and the snapshot on success). + """ + out_dir = Path(out_dir) + wanted = (inst.schema_name, inst.schema_version) + if local_path is not None: + return _ingest_local(inst, Path(local_path).expanduser(), wanted) + if offline: + return _from_files(inst, out_dir) + + now = now or utc_now() + commit, doc, errors, outcome = None, None, [], "ok" + try: + commit = resolve_commit(inst.github, inst.branch) + raw = fetch_at(inst.github, commit, inst.summary_path) + try: + doc = json.loads(raw) + except ValueError as exc: + outcome, errors = "invalid", [f"{inst.summary_path} is not JSON ({exc})"] + else: + outcome, errors = summary_mod.classify(doc, wanted) + except FetchError as exc: + outcome, errors = "unavailable", [str(exc)] + + snap_file = snapshot_path(out_dir, inst.instance) + if outcome == "ok": + _carry( + snap_file, + { + "instance": inst.instance, + "repo": inst.repo, + "github": inst.github, + "summary_path": inst.summary_path, + "commit": commit, + "fetched_at": now, + "summary": doc, + }, + ) + last_good = read_snapshot(out_dir, inst.instance) + receipt = { + "instance": inst.instance, + "repo": inst.repo, + "github": inst.github, + "branch": inst.branch, + "resolved_commit": commit, + "summary_path": inst.summary_path, + "source": "remote", + "fetched_at": now, + "outcome": outcome, + "schema": doc.get("schema") if isinstance(doc, dict) else None, + "version": doc.get("version") if isinstance(doc, dict) else None, + "record_count": len(doc["records"]) + if isinstance(doc, dict) and isinstance(doc.get("records"), list) + else None, + "errors": errors, + "cached_from": last_good.get("fetched_at") if last_good and outcome != "ok" else None, + } + _carry(receipt_path(out_dir, inst.instance), receipt) + return _from_files(inst, out_dir) + + +def _git(checkout: Path, *args: str) -> str | None: + try: + proc = subprocess.run( + ["git", "-C", str(checkout), *args], capture_output=True, text=True, timeout=20 + ) + except (OSError, subprocess.SubprocessError): + return None + return proc.stdout if proc.returncode == 0 else None + + +def _ingest_local(inst: Instance, path: Path, wanted) -> Snapshot: + file = path / inst.summary_path if path.is_dir() else path + view = Snapshot(inst, "ok", "local", checkout=str(file.parent), fetched_at=utc_now()) + view.attempt_at = view.fetched_at + top = _git(file.parent, "rev-parse", "--show-toplevel") + if top: + checkout = Path(top.strip()) + view.checkout = str(checkout) + head = _git(checkout, "rev-parse", "HEAD") + view.commit = head.strip() if head else None + status = _git(checkout, "status", "--porcelain") + view.dirty = bool(status.strip()) if status is not None else None + view.attempt_commit = view.commit + try: + view.doc = json.loads(file.read_text()) + except OSError as exc: + view.outcome, view.errors = "unavailable", [f"{file}: {exc}"] + return view + except ValueError as exc: + view.outcome, view.errors = "invalid", [f"{file} is not JSON ({exc})"] + view.doc = None + return view + view.outcome, view.errors = summary_mod.classify(view.doc, wanted) + if view.failed: + view.doc = None + return view diff --git a/pulse/registry.py b/pulse/registry.py new file mode 100644 index 0000000..d3e8e69 --- /dev/null +++ b/pulse/registry.py @@ -0,0 +1,277 @@ +"""Read and validate ``registry.yaml``, the one-row-per-instance registry. + +A row names its project by a PyAutoMind body-map identity (``repo``). The +project's location (``path``) and GitHub home (``github``) are read from +``PyAutoMind/repos.yaml`` when the registry is loaded, so the organ never keeps +a second catalogue of repositories (the spec's "Proposed project registry"). +""" + +from __future__ import annotations + +import os +import re +from dataclasses import dataclass +from pathlib import Path + +import yaml + +from pulse import ORGAN_ROOT + +REGISTRY_PATH = ORGAN_ROOT / "registry.yaml" +REGISTRY_SCHEMA = 1 +MIND_REPO = "PyAutoMind" # an organ name, not an instance fact +BODY_MAP = "repos.yaml" +BRANCH = "main" # the branch every ingest resolves to one commit + +REQUIRED = ("instance", "repo", "summary_path", "supported_schema", "dashboard_url") +FIELDS = (*REQUIRED, "library_refs", "cortex_project") + +_KEY = re.compile(r"^[a-z][a-z0-9_-]*$") +_GITHUB = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") +_SCHEMA = re.compile(r"^([a-z][a-z0-9-]*)@([1-9][0-9]*)$") + + +class RegistryError(ValueError): + """``registry.yaml`` (or the body map it resolves through) is malformed; + the message lists every problem.""" + + +@dataclass(frozen=True) +class Instance: + instance: str + repo: str + summary_path: str + supported_schema: str + dashboard_url: str + library_refs: tuple[str, ...] = () + cortex_project: str | None = None + # Resolved from the body map, never written in registry.yaml. + path: str = "" + github: str = "" + branch: str = BRANCH + + @property + def name(self) -> str: + return self.instance + + @property + def github_url(self) -> str: + return f"https://github.com/{self.github}" + + @property + def schema_name(self) -> str: + return _SCHEMA.match(self.supported_schema)[1] + + @property + def schema_version(self) -> int: + return int(_SCHEMA.match(self.supported_schema)[2]) + + def blob_url(self, commit: str | None, path: str) -> str: + """The GitHub page of ``path`` at ``commit`` (the branch when unknown).""" + return f"{self.github_url}/blob/{commit or self.branch}/{path}" + + def tree_url(self, commit: str | None) -> str: + return f"{self.github_url}/tree/{commit or self.branch}" + + +# ------------------------------------------------------------- body map --- + + +def workspace_roots(root: Path | None = None) -> list[Path]: + """Candidate workspace roots, most specific first.""" + if root is not None: + return [Path(root)] + roots = [] + env = os.environ.get("PYAUTO_ROOT") + if env: + roots.append(Path(env).expanduser()) + # organs/PyAutoPulse (grouped canonical) or /PyAutoPulse (flat bundle). + roots += [ORGAN_ROOT.parent.parent, ORGAN_ROOT.parent] + return roots + + +def mind_candidates(mind: Path | str | None = None) -> list[Path]: + """Where the PyAutoMind checkout is looked for, in order. + + An explicit ``--mind PATH`` first, then ``$PYAUTO_MIND``, then + ``$PYAUTO_ROOT/organs/PyAutoMind`` and ``$PYAUTO_ROOT/PyAutoMind``, then + beside this organ (grouped ``organs/`` or flat bundle layout). + """ + out: list[Path] = [] + if mind is not None: + out.append(Path(mind).expanduser()) + env = os.environ.get("PYAUTO_MIND") + if env: + out.append(Path(env).expanduser()) + for base in workspace_roots(): + out += [base / "organs" / MIND_REPO, base / MIND_REPO] + return out + + +def body_map_path(mind: Path | str | None = None) -> Path: + """``PyAutoMind/repos.yaml``; raise RegistryError when none is found. + + An explicit ``mind`` that holds no body map is an error, never a silent + fall-through to another checkout. + """ + if mind is not None: + path = Path(mind).expanduser() / BODY_MAP + if path.is_file(): + return path + raise RegistryError(f"--mind {mind}: no {BODY_MAP} there") + for candidate in mind_candidates(): + path = candidate / BODY_MAP + if path.is_file(): + return path + raise RegistryError( + f"cannot find {MIND_REPO}/{BODY_MAP} (the body map that resolves each instance's " + "repo); pass --mind PATH or set PYAUTO_MIND" + ) + + +def load_body_map(mind: Path | str | None = None) -> dict[str, dict]: + """``{repo name: {path, github, …}}`` from the Mind body map.""" + path = body_map_path(mind) + try: + doc = yaml.safe_load(path.read_text()) + except (OSError, yaml.YAMLError) as exc: + raise RegistryError(f"{path}: {exc}") from exc + repos = doc.get("repos") if isinstance(doc, dict) else None + if not isinstance(repos, dict): + raise RegistryError(f"{path}: no `repos:` mapping") + return {str(k): v for k, v in repos.items() if isinstance(v, dict)} + + +# ------------------------------------------------------------- registry --- + + +def _safe_relative(value: str) -> bool: + return ( + bool(value) + and not value.startswith("/") + and "://" not in value + and ".." not in value.split("/") + and "\\" not in value + ) + + +def validate(data, body_map: dict[str, dict] | None = None) -> list[str]: + """Return every problem with a parsed registry document (empty = valid). + + With ``body_map`` (``load_body_map()``), each ``repo`` and every + ``library_refs`` entry must also be a body-map identity, and each repo must + carry a ``github`` home there. + """ + if not isinstance(data, dict): + return ["registry is not a mapping"] + problems = [] + if data.get("schema") != REGISTRY_SCHEMA: + problems.append(f"schema must be {REGISTRY_SCHEMA}, got {data.get('schema')!r}") + rows = data.get("instances") + if not isinstance(rows, list) or not rows: + return problems + ["instances must be a non-empty list"] + seen: set[str] = set() + scopes: dict[tuple[str, str], str] = {} + for i, row in enumerate(rows): + where = f"instances[{i}]" + if not isinstance(row, dict): + problems.append(f"{where} is not a mapping") + continue + where = f"instance {row.get('instance', i)!r}" + for key in REQUIRED: + value = row.get(key) + if not isinstance(value, str) or not value.strip(): + problems.append(f"{where}: {key} is missing or empty") + unknown = sorted(set(row) - set(FIELDS)) + if unknown: + problems.append(f"{where}: unknown field(s) {', '.join(unknown)}") + key = row.get("instance") + if isinstance(key, str): + if not _KEY.match(key): + problems.append(f"{where}: instance must match {_KEY.pattern}") + if key in seen: + problems.append(f"{where}: duplicate instance") + seen.add(key) + path = row.get("summary_path") + if isinstance(path, str) and not _safe_relative(path): + problems.append(f"{where}: summary_path must be a relative path inside the repo") + schema = row.get("supported_schema") + if isinstance(schema, str) and not _SCHEMA.match(schema): + problems.append(f"{where}: supported_schema must be @") + url = row.get("dashboard_url") + if isinstance(url, str) and not url.startswith("https://"): + problems.append(f"{where}: dashboard_url must be an https:// URL") + refs = row.get("library_refs", []) + if refs is None: + refs = [] + if not isinstance(refs, list) or not all(isinstance(r, str) and r for r in refs): + problems.append(f"{where}: library_refs must be a list of body-map repo names") + refs = [] + cortex = row.get("cortex_project") + if cortex is not None and not (isinstance(cortex, str) and cortex.strip()): + problems.append(f"{where}: cortex_project must be a Cortex key or null") + repo = row.get("repo") + if isinstance(repo, str) and isinstance(path, str): + # Disjoint scopes: one summary is registered once, never twice under + # two names to inflate coverage. + other = scopes.get((repo, path)) + if other is not None: + problems.append(f"{where}: {repo}:{path} is already registered as {other!r}") + scopes[(repo, path)] = str(key) + if body_map is not None: + if isinstance(repo, str) and repo: + entry = body_map.get(repo) + if entry is None: + problems.append(f"{where}: repo {repo!r} is not in the body map") + else: + gh = entry.get("github") + if not (isinstance(gh, str) and _GITHUB.match(gh)): + problems.append(f"{where}: body map has no github owner/repo for {repo!r}") + missing = [r for r in refs if r not in body_map] + if missing: + problems.append(f"{where}: library_refs not in the body map: {', '.join(missing)}") + return problems + + +def load( + path: Path | str = REGISTRY_PATH, + mind: Path | str | None = None, + body_map: dict[str, dict] | None = None, +) -> list[Instance]: + """Parse and validate the registry, resolving each repo through the body + map; raise RegistryError on any problem.""" + path = Path(path) + try: + data = yaml.safe_load(path.read_text()) + except (OSError, yaml.YAMLError) as exc: + raise RegistryError(f"{path}: {exc}") from exc + if body_map is None: + body_map = load_body_map(mind) + problems = validate(data, body_map) + if problems: + raise RegistryError(f"{path}:\n " + "\n ".join(problems)) + out = [] + for row in data["instances"]: + entry = body_map[row["repo"]] + out.append( + Instance( + instance=row["instance"], + repo=row["repo"], + summary_path=row["summary_path"], + supported_schema=row["supported_schema"], + dashboard_url=row["dashboard_url"], + library_refs=tuple(row.get("library_refs") or ()), + cortex_project=row.get("cortex_project"), + path=str(entry.get("path") or row["repo"]), + github=str(entry["github"]), + ) + ) + return out + + +def get(instances: list[Instance], name: str) -> Instance: + for instance in instances: + if instance.instance == name: + return instance + known = ", ".join(i.instance for i in instances) + raise RegistryError(f"no instance {name!r} in the registry (known: {known})") diff --git a/pulse/summary.py b/pulse/summary.py new file mode 100644 index 0000000..73e998c --- /dev/null +++ b/pulse/summary.py @@ -0,0 +1,411 @@ +"""The ``profiling-summary`` v1 exchange contract, as the organ reads it. + +The contract is owned by the producer and documented beside it +(``autolens_profiling/dashboard/README.md``, "summary.json — the +profiling-summary v1 read contract": Envelope / Records / Comparisons). This +module validates the **exchange** contract only — known schema/version, +required fields, unique ids, finite numerics, UTC dates, safe evidence paths, +axis/unit consistency — and pairs each producer comparison with its two +records so the board can refuse a pair whose axis or hardware identity +differs. It never judges a timing, never recomputes a ratio and has no +project-specific branch: every producer behind the contract takes the same +code path. Stdlib only; no scientific library is imported. +""" + +from __future__ import annotations + +import math +import re +from dataclasses import dataclass, field +from datetime import datetime + +SUPPORTED = {("profiling-summary", 1)} + +ENVELOPE = ( + "schema", + "version", + "project", + "scope", + "generated_at", + "evidence_updated_at", + "producer_revision", + "comparison_policy", + "coverage", + "records", + "comparisons", + "limitations", +) + +# The measurement axis table. A value's unit must belong to its axis: a memory +# value can never enter a seconds series, and vice versa. +AXIS_UNITS = { + "runtime": {"s"}, + "compile": {"s"}, + "breakdown": {"s"}, + "memory": {"B", "KiB", "MiB", "GiB", "KB", "MB", "GB"}, +} +STATUSES = {"drifted", "improved", "flat", "insufficient"} +HARDWARE = ("device", "backend", "precision", "host") + +_SHA = re.compile(r"^[0-9a-f]{40}$") + + +# ------------------------------------------------------------ primitives --- + + +def parse_utc(value) -> datetime | None: + """A datetime for an ISO-8601 timestamp that says it is UTC, else None.""" + if not isinstance(value, str): + return None + if value.endswith("Z"): + text = value[:-1] + "+00:00" + elif value.endswith("+00:00"): + text = value + else: + return None + try: + parsed = datetime.fromisoformat(text) + except ValueError: + return None + off = parsed.utcoffset() + return parsed if off is not None and off.total_seconds() == 0 else None + + +def _number(value) -> bool: + return isinstance(value, int | float) and not isinstance(value, bool) + + +def _finite_or_null(value) -> bool: + return value is None or (_number(value) and math.isfinite(value)) + + +def safe_relative_path(value) -> bool: + """Repo-relative: not absolute, no ``..``, no URL, no backslash.""" + return ( + isinstance(value, str) + and bool(value) + and not value.startswith("/") + and "://" not in value + and "\\" not in value + and ".." not in value.split("/") + ) + + +def _text(value) -> bool: + return isinstance(value, str) and bool(value.strip()) + + +# ------------------------------------------------------------- validation --- + + +def supported(doc, wanted: tuple[str, int] | None = None) -> str | None: + """None when the doc's (schema, version) is readable here, else why not. + + ``wanted`` is the registry row's ``supported_schema``; the doc must match + it *and* be one this reader implements. + """ + if not isinstance(doc, dict): + return "summary is not a JSON object" + got = (doc.get("schema"), doc.get("version")) + if got not in SUPPORTED: + known = ", ".join(f"{s}@{v}" for s, v in sorted(SUPPORTED)) + return f"unsupported schema {got[0]!r} version {got[1]!r} (this reader supports {known})" + if wanted is not None and got != tuple(wanted): + return f"schema {got[0]}@{got[1]} is not the registered {wanted[0]}@{wanted[1]}" + return None + + +def validate(doc) -> list[str]: + """Every exchange-contract break in a parsed summary (empty = valid). + + Schema/version support is checked separately by ``supported``; this + checks the v1 shape. + """ + if not isinstance(doc, dict): + return ["summary is not a JSON object"] + out = [f"missing required field {k!r}" for k in ENVELOPE if k not in doc] + for key in ("project", "scope"): + if key in doc and not _text(doc[key]): + out.append(f"{key} must be a non-empty string") + if "generated_at" in doc and parse_utc(doc["generated_at"]) is None: + out.append(f"generated_at is not an ISO-8601 UTC timestamp: {doc['generated_at']!r}") + evidence = doc.get("evidence_updated_at") + if "evidence_updated_at" in doc: + if evidence is None: + if not _text(doc.get("evidence_updated_at_reason")): + out.append("evidence_updated_at is null without evidence_updated_at_reason") + elif parse_utc(evidence) is None: + out.append(f"evidence_updated_at is not an ISO-8601 UTC timestamp: {evidence!r}") + valid_until = doc.get("valid_until") + if valid_until is not None: + vu = parse_utc(valid_until) + if vu is None: + out.append(f"valid_until is not an ISO-8601 UTC timestamp or null: {valid_until!r}") + else: + ev = parse_utc(evidence) + if ev is not None and vu < ev: + out.append("valid_until precedes evidence_updated_at") + rev = doc.get("producer_revision") + if rev is not None and not (isinstance(rev, str) and _SHA.match(rev)): + out.append(f"producer_revision is not a 40-hex commit or null: {rev!r}") + policy = doc.get("comparison_policy") + if "comparison_policy" in doc and not (isinstance(policy, dict) and _text(policy.get("id"))): + out.append("comparison_policy must be an object with an id") + out += _validate_coverage(doc) + out += _validate_records(doc) + out += _validate_comparisons(doc) + lim = doc.get("limitations") + if "limitations" in doc and not (isinstance(lim, list) and all(_text(x) for x in lim)): + out.append("limitations must be a list of non-empty strings") + return out + + +def _validate_coverage(doc) -> list[str]: + if "coverage" not in doc: + return [] + cov = doc["coverage"] + if not isinstance(cov, dict): + return ["coverage is not an object"] + out = [] + if not isinstance(cov.get("expected"), dict): + out.append("coverage.expected must be an object") + obs = cov.get("observed") + if not isinstance(obs, dict): + out.append("coverage.observed must be an object") + else: + for k, v in obs.items(): + if not (isinstance(v, int) and not isinstance(v, bool) and v >= 0): + out.append(f"coverage.observed.{k} is not a non-negative integer") + excluded = cov.get("excluded", []) + if not isinstance(excluded, list): + return out + ["coverage.excluded must be a list"] + for i, x in enumerate(excluded): + if not isinstance(x, dict): + out.append(f"coverage.excluded[{i}] is not an object") + continue + if not _text(x.get("id")) or not _text(x.get("reason")): + out.append(f"coverage.excluded[{i}] needs an id and a reason") + ev = x.get("evidence") if isinstance(x.get("evidence"), dict) else {} + if not safe_relative_path(ev.get("path")): + out.append(f"coverage.excluded[{i}] evidence path is not safe: {ev.get('path')!r}") + return out + + +def _validate_records(doc) -> list[str]: + records = doc.get("records") + if "records" in doc and not isinstance(records, list): + return ["records is not a list"] + out = [] + seen: set[str] = set() + for i, r in enumerate(records or []): + where = f"records[{i}]" + if not isinstance(r, dict): + out.append(f"{where} is not an object") + continue + rid = r.get("id") + if not _text(rid): + out.append(f"{where} has no id") + elif rid in seen: + out.append(f"duplicate record id {rid!r}") + else: + seen.add(rid) + where = f"record {rid!r}" + axis, unit = r.get("axis"), r.get("unit") + if axis not in AXIS_UNITS: + out.append(f"{where}: axis {axis!r} is not one of {', '.join(sorted(AXIS_UNITS))}") + elif unit not in AXIS_UNITS[axis]: + out.append( + f"{where}: unit {unit!r} is not a {axis} unit " + f"({', '.join(sorted(AXIS_UNITS[axis]))}); a value cannot enter a series " + "of another unit" + ) + meas = r.get("measurement") + if not isinstance(meas, dict) or not meas: + out.append(f"{where}: measurement must be a non-empty object") + else: + if not all(_finite_or_null(v) for v in meas.values()): + out.append(f"{where}: measurement carries a non-finite or non-numeric value") + if all(v is None for v in meas.values()): + out.append(f"{where}: measurement carries no value") + ident = r.get("identity") + if not isinstance(ident, dict): + out.append(f"{where}: identity must be an object") + else: + missing = [k for k in ("device", "backend", "precision") if k not in ident] + if missing: + out.append( + f"{where}: identity lacks {', '.join(missing)} (null + reason if unknown)" + ) + prov = r.get("provenance") + if not isinstance(prov, dict): + out.append(f"{where}: provenance must be an object") + else: + for k in ("has_provenance", "qualified"): + if not isinstance(prov.get(k), bool): + out.append(f"{where}: provenance.{k} must be a boolean") + if "host" not in prov: + out.append(f"{where}: provenance lacks host (null if unknown)") + for k, v in prov.items(): + if _number(v) and not math.isfinite(v): + out.append(f"{where}: provenance.{k} is non-finite") + ev = r.get("evidence") + if not isinstance(ev, dict) or not safe_relative_path(ev.get("path")): + path = ev.get("path") if isinstance(ev, dict) else None + out.append(f"{where}: evidence path is not a safe repo-relative path: {path!r}") + return out + + +def _validate_comparisons(doc) -> list[str]: + comparisons = doc.get("comparisons") + if "comparisons" in doc and not isinstance(comparisons, list): + return ["comparisons is not a list"] + policy = doc.get("comparison_policy") + policy_id = policy.get("id") if isinstance(policy, dict) else None + out = [] + seen: set[str] = set() + for i, c in enumerate(comparisons or []): + where = f"comparisons[{i}]" + if not isinstance(c, dict): + out.append(f"{where} is not an object") + continue + key = c.get("comparison_key") + if not _text(key): + out.append(f"{where} has no comparison_key") + elif key in seen: + out.append(f"duplicate comparison_key {key!r}") + else: + seen.add(key) + where = f"comparison {key!r}" + if c.get("policy") != policy_id: + out.append(f"{where}: policy {c.get('policy')!r} is not comparison_policy.id") + if c.get("axis") not in AXIS_UNITS: + out.append(f"{where}: axis {c.get('axis')!r} is not in the axis table") + if not _text(c.get("metric")): + out.append(f"{where}: metric must be a non-empty string") + if c.get("status") not in STATUSES: + out.append(f"{where}: status {c.get('status')!r} is not in the contract") + if not _finite_or_null(c.get("ratio")): + out.append(f"{where}: ratio is non-finite or non-numeric") + if not isinstance(c.get("qualified"), bool): + out.append(f"{where}: qualified must be a boolean") + reasons = c.get("reasons") + if not (isinstance(reasons, list) and all(isinstance(x, str) for x in reasons)): + out.append(f"{where}: reasons must be a list of strings") + for end in ("baseline", "candidate"): + v = c.get(end) + if v is not None and not _text(v): + out.append(f"{where}: {end} must be a release reference or null") + return out + + +def classify(doc, wanted: tuple[str, int] | None = None) -> tuple[str, list[str]]: + """``(outcome, errors)``: ok | unsupported | invalid.""" + why = supported(doc, wanted) + if why: + return "unsupported", [why] + errors = validate(doc) + return ("invalid", errors) if errors else ("ok", []) + + +# ------------------------------------------------------------ comparisons --- + + +def hardware(record: dict) -> dict: + """The hardware identity a record was measured on (None = not recorded).""" + ident = record.get("identity") or {} + prov = record.get("provenance") or {} + return { + "device": ident.get("device"), + "backend": ident.get("backend"), + "precision": ident.get("precision"), + "host": prov.get("host"), + } + + +def group_label(hw: dict | None) -> str: + if hw is None: + return "unresolved" + parts = [str(hw[k]) if hw[k] is not None else f"{k} unknown" for k in HARDWARE[:3]] + return " · ".join(parts) + + +@dataclass +class Pair: + """One producer comparison and the records it names, as the board shows it.""" + + comparison: dict + baseline: dict | None = None + candidate: dict | None = None + refused: list[str] = field(default_factory=list) + group: str = "unresolved" + + @property + def key(self) -> str: + return self.comparison["comparison_key"] + + +def _record_id(key: str, ref: str) -> str: + # The contract's record id grammar: `@`. + return f"{key}@{ref}" + + +def pair(doc: dict) -> list[Pair]: + """Pair every comparison with its baseline/candidate records. + + A pair is **refused** (shown with its reason, its ratio never displayed + as a comparison) when an endpoint is not among the records, when the two + records' axes differ from each other or from the comparison's, or when + their hardware identity (device, backend, precision, host) differs. A host + is compared only when both records name one: an unrecorded host is + unknown, not different. Accepted pairs are grouped by hardware identity + so changed hardware is always a separate group, never merged. + """ + records = {r["id"]: r for r in doc.get("records") or [] if isinstance(r, dict) and "id" in r} + by_series: dict[str, dict] = {} + for rid, r in records.items(): + by_series.setdefault(rid.rpartition("@")[0], r) + out = [] + for c in doc.get("comparisons") or []: + p = Pair(c) + key = c["comparison_key"] + for end in ("baseline", "candidate"): + ref = c.get(end) + if ref is None: + continue + rec = records.get(_record_id(key, ref)) + if rec is None: + p.refused.append(f"{end} record {_record_id(key, ref)!r} is not in records") + setattr(p, end, rec) + ends = [r for r in (p.baseline, p.candidate) if r is not None] + axes = {r.get("axis") for r in ends} + if len(axes) > 1: + p.refused.append( + f"axis mismatch: baseline {p.baseline.get('axis')} vs candidate " + f"{p.candidate.get('axis')} — never combined" + ) + elif axes and c.get("axis") not in axes: + p.refused.append(f"axis mismatch: comparison {c.get('axis')} vs records {axes.pop()}") + if p.baseline is not None and p.candidate is not None: + a, b = hardware(p.baseline), hardware(p.candidate) + changed = [ + k + for k in HARDWARE + if a[k] != b[k] and not (k == "host" and (a[k] is None or b[k] is None)) + ] + if changed: + diffs = ", ".join(f"{k} {a[k]} → {b[k]}" for k in changed) + p.refused.append(f"hardware identity changed ({diffs}) — separate groups") + anchor = p.candidate or p.baseline or by_series.get(key) + p.group = "refused" if p.refused else group_label(hardware(anchor) if anchor else None) + out.append(p) + return out + + +def qualified_records(doc: dict) -> int: + """Records the producer marks qualified; unknown provenance never counts.""" + return sum( + 1 + for r in doc.get("records") or [] + if (r.get("provenance") or {}).get("qualified") is True + and (r.get("provenance") or {}).get("has_provenance") is True + ) diff --git a/receipts/lens.json b/receipts/lens.json new file mode 100644 index 0000000..b67b129 --- /dev/null +++ b/receipts/lens.json @@ -0,0 +1,16 @@ +{ + "instance": "lens", + "repo": "autolens_profiling", + "github": "PyAutoLabs/autolens_profiling", + "branch": "main", + "resolved_commit": "d9f385f002803b822a6293d7bd20113d2611dca1", + "summary_path": "dashboard/summary.json", + "source": "remote", + "fetched_at": "2026-10-02T12:03:46Z", + "outcome": "ok", + "schema": "profiling-summary", + "version": 1, + "record_count": 159, + "errors": [], + "cached_from": null +} diff --git a/registry.yaml b/registry.yaml new file mode 100644 index 0000000..62534b2 --- /dev/null +++ b/registry.yaml @@ -0,0 +1,14 @@ +# registry.yaml — the PyAutoPulse instance registry: one row per project that +# publishes a profiling summary. A row names the project by its PyAutoMind +# body-map identity (`repo`); the repository's location and GitHub home are +# read from PyAutoMind/repos.yaml at run time, never copied here. Schema and +# the rules for adding a row: REFERENCE.md ("Registry"). +schema: 1 +instances: + - instance: lens + repo: autolens_profiling + summary_path: dashboard/summary.json + supported_schema: profiling-summary@1 + dashboard_url: https://pyautolabs.github.io/autolens_profiling/ + library_refs: [PyAutoLens, PyAutoGalaxy, PyAutoArray, PyAutoFit] + cortex_project: null diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..5acfdcf --- /dev/null +++ b/ruff.toml @@ -0,0 +1,46 @@ +# ruff configuration for PyAutoPulse. +# +# PyAutoPulse is an organ, not an installable package: there is no pyproject.toml, +# and `bin/pyauto-pulse` puts the repo root on sys.path so `pulse/` imports by its +# top-level name. A standalone ruff.toml at the repository root is the supported +# configuration location for that case (see https://docs.astral.sh/ruff/configuration/). +# The rule set was inherited from PyAutoEyes (via autolens_visualization, copied from +# autolens_profiling) and is kept deliberately conservative. + +target-version = "py311" +line-length = 100 + +# Exclude generated / external folders. +extend-exclude = [ + ".venv", + "venv", +] + +[lint] +# Conservative selection — catch real bugs without imposing a strict style. +# Profiling scripts use scientific patterns that can clash with stricter rule +# sets (long lines for table headers, `if __name__ == "__main__":` is rare +# because scripts run top-level, etc.). +select = [ + "E", # pycodestyle errors + "F", # pyflakes (undefined names, unused imports) + "W", # pycodestyle warnings + "I", # isort (import order) + "UP", # pyupgrade (Python version idioms) + "B", # flake8-bugbear (likely bugs) +] +ignore = [ + "E501", # long lines — common in scientific code; ruff format handles wrapping + "E402", # module-level imports not at top of file — profiling scripts often + # set env vars (NUMBA_CACHE_DIR etc.) before importing autolens + "F401", # unused imports — some scripts deliberately import-for-side-effect + # (e.g. `from autoconf import jax_wrapper # noqa: F401`) + "B008", # function call in default argument — common autofit pattern + "B905", # zip() without strict= — scripts zip equal-length lists they built + # themselves; threading strict= through adds noise, not safety + "B007", # unused loop-control variable — warm-up/repeat loops (`for _i in + # range(n)`) are the dominant pattern in timing code +] + +[format] +# Defaults: black-compatible. Nothing to override. diff --git a/snapshots/lens.json b/snapshots/lens.json new file mode 100644 index 0000000..5fe8a9d --- /dev/null +++ b/snapshots/lens.json @@ -0,0 +1,7711 @@ +{ + "instance": "lens", + "repo": "autolens_profiling", + "github": "PyAutoLabs/autolens_profiling", + "summary_path": "dashboard/summary.json", + "commit": "d9f385f002803b822a6293d7bd20113d2611dca1", + "fetched_at": "2026-10-02T12:03:46Z", + "summary": { + "schema": "profiling-summary", + "version": 1, + "project": "autolens_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T19:43:00Z", + "evidence_updated_at": "2026-08-17T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "227b5c919b1c205962427a6f48fe233770220a69", + "comparison_policy": { + "id": "runtime-drift-2x-1ms", + "ratio": 2.0, + "floor_s": 0.001, + "reference_host": "euclid-ral-gpu-2", + "loadavg_cap": 8.0 + }, + "coverage": { + "expected": { + "sections": [ + "runtime", + "breakdown", + "simulators", + "lens" + ], + "cells": null, + "reason": "no declared cell matrix; the results/ scan is the inventory" + }, + "observed": { + "series": 145, + "points": 159, + "releases": 4, + "cells": 61 + }, + "excluded": [ + { + "id": "breakdown:interferometer/sdp81/delaunay/sdp81:hpc_a100_fp64@2026.8.17.1", + "reason": "loadavg 65.7 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/delaunay_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1", + "reason": "loadavg 68.3 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/delaunay_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64@2026.8.17.1", + "reason": "loadavg 55.7 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/mge/sdp81:hpc_a100_fp64_sparse@2026.8.17.1", + "reason": "loadavg 55.7 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/mge_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/pixelization/sdp81:hpc_a100_fp64@2026.8.17.1", + "reason": "loadavg 65.7 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/pixelization_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1", + "reason": "loadavg 68.3 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/pixelization_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + } + ] + }, + "records": [ + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 16.729484930000034, + "vmap_per_call_s": 12.66077735333335 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.523518409999815, + "vmap_per_call_s": 3.774630096666685 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/delaunay_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.144032109999898, + "vmap_per_call_s": 5.215584503333351 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 17.836323139999877, + "vmap_per_call_s": 16.029278730000076 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.485923779999939, + "vmap_per_call_s": 4.950758379999995 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/delaunay/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.06495481780730188, + "vmap_per_call_s": 0.04253356978151714 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07075177289079874, + "vmap_per_call_s": 0.04804177490004804 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/delaunay_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay/jwst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 48.81026199999978, + "vmap_per_call_s": 26.22635450333328 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/jwst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/jwst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/delaunay/jwst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 10.423912969999947, + "vmap_per_call_s": 12.300888043333423 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/jwst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/jwst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/delaunay/jwst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 22.427841500000067, + "vmap_per_call_s": 19.50632631999979 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/jwst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/jwst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/delaunay/jwst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 14.046471999999994, + "vmap_per_call_s": 12.850469253333358 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/jwst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/jwst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/delaunay_nn/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 5.208032309999908, + "vmap_per_call_s": 4.252231736666727 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay_nn/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay_nn/delaunay_nn_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay_nn/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07340575398411602, + "vmap_per_call_s": 0.046442550668143665 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay_nn/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay_nn/delaunay_nn_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.08009085720404982, + "vmap_per_call_s": 0.04925385855603963 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay_nn/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay_nn/delaunay_nn_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay_numba/euclid:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.24339530000179366, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay_numba/euclid", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay_numba/delaunay_numba_likelihood_summary_euclid_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay_numba/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.969045499998174, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay_numba/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay_numba/delaunay_numba_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/mge/ao:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.108424629999354, + "vmap_per_call_s": 4.922238283333475 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/ao", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/ao/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge/ao:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 5.712817799999902, + "vmap_per_call_s": 4.022985576666785 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/ao", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/ao/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.11771118000033312, + "vmap_per_call_s": 0.1651308966667178 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07903557000008732, + "vmap_per_call_s": 0.11596217666665325 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/mge_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.2561067099999491, + "vmap_per_call_s": 0.18706581000005826 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/hst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.16434103999999933, + "vmap_per_call_s": 0.17893060666683594 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/hst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.14046013000006496, + "vmap_per_call_s": 0.22278538333327258 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/hst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/mge/jwst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.7161960399993405, + "vmap_per_call_s": 0.5747806300001684 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/jwst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/jwst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge/jwst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.38725629000000483, + "vmap_per_call_s": 0.3817480200000622 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/jwst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/jwst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/mge/jwst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.6784522000001744, + "vmap_per_call_s": 0.5270821000000675 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/jwst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/jwst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/mge/jwst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.488690349999888, + "vmap_per_call_s": 0.380645530000038 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/jwst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/jwst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/mge_mass_jax/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.35121137999995, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge_mass_jax/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge_mass_jax/mge_mass_jax_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 13.724898559999565, + "vmap_per_call_s": 12.49813459666669 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.1860993599999348, + "vmap_per_call_s": 4.622900409999965 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/pixelization_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 5.789975740000227, + "vmap_per_call_s": 5.159429313333264 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/hst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 14.778166580000107, + "vmap_per_call_s": 13.053871076666837 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/hst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 5.246675999999934, + "vmap_per_call_s": 6.418966320000012 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/hst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/pixelization/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.050628519617021084, + "vmap_per_call_s": 0.03207861754926853 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.057630352000705896, + "vmap_per_call_s": 0.036653317512536886 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/pixelization_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization/jwst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 21.778462779999973, + "vmap_per_call_s": 28.32046649666663 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/jwst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/jwst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/pixelization/jwst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 9.566611529999864, + "vmap_per_call_s": 9.69070508666664 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/jwst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/jwst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:imaging/pixelization/jwst:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 43.58491838000045, + "vmap_per_call_s": 29.38957891000003 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/jwst", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/jwst/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:imaging/pixelization/jwst:local_cpu_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 9.420377540000118, + "vmap_per_call_s": 9.474230743333221 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/jwst", + "config": "local_cpu_mp", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/jwst/comparison.json", + "fragment": "local_cpu_mp_sparse" + } + }, + { + "id": "runtime:imaging/pixelization_numba/euclid:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5853628500008199, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization_numba/euclid", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization_numba/pixelization_numba_likelihood_summary_euclid_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization_numba/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.4185542499999428, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization_numba/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization_numba/pixelization_numba_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization_numba_mge_mass/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.3022493000007671, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization_numba_mge_mass/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization_numba_mge_mass/pixelization_numba_mge_mass_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:interferometer/delaunay/alma:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 6.505125349999981, + "vmap_per_call_s": 7.765058916666658 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/delaunay/alma", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/delaunay/alma/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:interferometer/delaunay/sma:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.576843710000003, + "vmap_per_call_s": 2.360147706666665 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/delaunay/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/delaunay/sma/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:interferometer/delaunay/sma:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.342003539999996, + "vmap_per_call_s": 2.6039572800000013 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/delaunay/sma", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/delaunay/sma/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:interferometer/mge/sma:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.23072274000005563, + "vmap_per_call_s": 0.2370947499999602 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/mge/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/mge/sma/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:interferometer/mge/sma:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.23150078000035137, + "vmap_per_call_s": 0.2546015333333344 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/mge/sma", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/mge/sma/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:interferometer/pixelization/sma:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.0423672299999454, + "vmap_per_call_s": 2.025886699999925 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/pixelization/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/pixelization/sma/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:interferometer/pixelization/sma:local_cpu_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.38713332000043, + "vmap_per_call_s": 2.476506526666587 + }, + "identity": { + "section": "runtime", + "cell": "interferometer/pixelization/sma", + "config": "local_cpu_mp", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/interferometer/pixelization/sma/comparison.json", + "fragment": "local_cpu_mp" + } + }, + { + "id": "runtime:point_source_image/image_plane_solved:local_cpu_fp64@2026.7.23.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.03859548000036739, + "vmap_per_call_s": 0.028134080000018002 + }, + "identity": { + "section": "runtime", + "cell": "point_source_image/image_plane_solved", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": null, + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.23.1", + "release_date": "2026-07-23", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/point_source_image/image_plane_solved/image_plane_solved_summary_v2026.7.23.1.json", + "fragment": null + } + }, + { + "id": "runtime:point_source_source/source_plane_solved:local_cpu_fp64@2026.7.23.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0003383600000233855, + "vmap_per_call_s": 0.00011812666683302571 + }, + "identity": { + "section": "runtime", + "cell": "point_source_source/source_plane_solved", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": null, + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.23.1", + "release_date": "2026-07-23", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/point_source_source/source_plane_solved/source_plane_solved_summary_v2026.7.23.1.json", + "fragment": null + } + }, + { + "id": "runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.00025833239778876304, + "vmap_per_call_s": 9.664240060374141e-05 + }, + "identity": { + "section": "runtime", + "cell": "point_source_source/source_plane_solved", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": "366911", + "loadavg": 0.16, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/runtime/point_source_source/source_plane_solved/comparison.json", + "fragment": "hpc_ral_cpu_fp64" + } + }, + { + "id": "runtime:point_source_source/source_plane_solved:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0006424111023079603, + "vmap_per_call_s": 5.645434339385247e-06 + }, + "identity": { + "section": "runtime", + "cell": "point_source_source/source_plane_solved", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": "366912", + "loadavg": 1.16, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/runtime/point_source_source/source_plane_solved/comparison.json", + "fragment": "hpc_a100_fp64" + } + }, + { + "id": "breakdown:cluster/image_plane:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.98938516666658, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_breakdown_v2026.7.6.649.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/image_plane:local_cpu_fp64@2026.7.23.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 10.24726366665709, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.23.1", + "release_date": "2026-07-23", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_breakdown_v2026.7.23.1.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/image_plane:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.809658799998337, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_local_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/image_plane:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.533296723850071, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-compute-10-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/source_plane:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0030934299999898942, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/source_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/source_plane_breakdown_v2026.7.6.649.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/source_plane:local_cpu_fp64@2026.7.23.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.004543420000845799, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/source_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.23.1", + "release_date": "2026-07-23", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/source_plane_breakdown_v2026.7.23.1.json", + "fragment": null + } + }, + { + "id": "breakdown:datacube/delaunay/alma_high:hpc_a100_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 7.033092858603777, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "datacube/delaunay/alma_high", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/datacube/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:datacube/delaunay/alma_high:hpc_a100_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 7.110641481298626, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "datacube/delaunay/alma_high", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/datacube/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:local_cpu_fp64@2026.5.29.4", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 11.28559362999995, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.5.29.4", + "release_date": "2026-05-29", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_breakdown_hst_v2026.5.29.4.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 10.07246866000096, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_breakdown_hst_v2026.7.6.649.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.338812999999573, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:local_cpu_fp64_sparse@2026.5.29.4", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 7.956636459999891, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.5.29.4", + "release_date": "2026-05-29", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_breakdown_hst_v2026.5.29.4_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 8.8120920699992, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_breakdown_hst_v2026.7.6.649_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.06747430935502052, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07373669410590082, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:hpc_a100_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.09684501230021852, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay/hst:hpc_a100_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.09550482990025558, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay/hst", + "config": "hpc_a100_mp", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_hpc_a100_mp_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay_nn/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.489110750001054, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay_nn/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_nn_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07490132919047027, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay_nn/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_nn_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.08473261788021773, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay_nn/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_nn_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay_numba/euclid:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.24589134999951057, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay_numba/euclid", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_numba_breakdown_euclid_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/delaunay_numba/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.2721871500016277, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/delaunay_numba/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/delaunay_numba_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/mge/hst:local_cpu_fp64@2026.5.29.4", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.1781961699999783, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.5.29.4", + "release_date": "2026-05-29", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/mge_breakdown_hst_v2026.5.29.4.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/mge/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.1794793600001867, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/mge_breakdown_hst_v2026.7.6.649.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/mge/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.04029415999993944, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/mge_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/mge/hst:hpc_a100_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.007760955000048853, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/mge/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:local_cpu_fp64@2026.5.29.4", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 7.794436039999999, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.5.29.4", + "release_date": "2026-05-29", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_breakdown_hst_v2026.5.29.4.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 8.648970759999793, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_breakdown_hst_v2026.7.6.649.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.4022613300006928, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:local_cpu_fp64_sparse@2026.5.29.4", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 8.93560222000001, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.5.29.4", + "release_date": "2026-05-29", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_breakdown_hst_v2026.5.29.4_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 10.174653820000458, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_breakdown_hst_v2026.7.6.649_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.06002094733994453, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07080817648675293, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:hpc_a100_mp@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.056415032700169836, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization/hst:hpc_a100_mp_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.05551908770012232, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization/hst", + "config": "hpc_a100_mp", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_hpc_a100_mp_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization_numba/euclid:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5385655499994755, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization_numba/euclid", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_numba_breakdown_euclid_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:imaging/pixelization_numba/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.059635450001224, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "imaging/pixelization_numba/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/imaging/pixelization_numba_breakdown_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 8.327951277674098, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/delaunay/alma_high", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/delaunay_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.10145363440096844, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/delaunay/alma_high", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.10026123700081371, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/delaunay/alma_high", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/delaunay_numba/alma_high:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 13.822086743002536, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/delaunay_numba/alma_high", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/delaunay_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.8786374194009117, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/mge/alma_high", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.019613086098979694, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/mge/alma_high", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/mge_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.9294628362004005, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/mge/alma_high", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/mge_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 7.600348007671225, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/pixelization/alma_high", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/pixelization_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.09587617579963989, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/pixelization/alma_high", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.09429437270009658, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/pixelization/alma_high", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/pixelization_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/alma_high/pixelization_numba/alma_high:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 19.026710038747346, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/alma_high/pixelization_numba/alma_high", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/alma_high/pixelization_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.246137866665474, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay/alma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.6964867200003937, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay/alma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay/alma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.049513059499440716, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay/alma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay/alma:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.049328355699253736, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay/alma", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.5316758499999197, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba/alma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.2653459818546635, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba/alma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.47196160000097925, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_direct_conv/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.4336043666674716, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_direct_conv/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_direct_conv_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_direct_conv/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.3641680100001395, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_direct_conv/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_direct_conv_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_jax/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 8.104913233333113, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_jax/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_jax_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_jax/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.20312447000033, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_jax/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_jax_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_reference/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.419525166665456, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_reference/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_reference_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_reference/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5166562200000044, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_reference/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_reference_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_source_loop/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.44236295000009707, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_source_loop/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_source_loop_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_symmetric/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.4463114799997129, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_symmetric/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_symmetric_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/delaunay_numba_two_stage/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.38060654000000793, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/delaunay_numba_two_stage/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/delaunay_numba_two_stage_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.563308475400845, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/delaunay/jvla", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5427425143003347, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/delaunay/jvla", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 23.81200230929971, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/mge/jvla", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.01671951220050687, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/mge/jvla", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/mge_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 23.71543760449931, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/mge/jvla", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/mge_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5643649918987649, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/pixelization/jvla", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5500911986993742, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/jvla/pixelization/jvla", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/jvla/pixelization_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 41.07626644999982, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/alma:local_cpu_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 13.10301575000085, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/alma", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_breakdown_alma_v2026.8.17.1_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/alma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.9432308470990393, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/alma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/alma:hpc_a100_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.002671858400572091, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/alma", + "config": "hpc_a100_fp64", + "sparse": true, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_hpc_a100_fp64_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/alma_high:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 144.5698579, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/alma_high", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_breakdown_alma_high_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.08686684999993304, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge/sma:local_cpu_fp64_sparse@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.08205540000017209, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge/sma", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_breakdown_sma_v2026.8.17.1_sparse.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/mge_dft/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.06162745999990875, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/mge_dft/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/mge_dft_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.221055499998329, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization/alma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 2.907665969338268, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization/alma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization/alma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.044458239999949, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization/alma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization/alma:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.04401827389956452, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization/alma", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.0613702799999374, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba/alma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.8345626964843464, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba/alma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.148083173685384, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_direct_conv/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.8367402000003494, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_direct_conv/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_direct_conv_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_direct_conv/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.1736454899997625, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_direct_conv/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_direct_conv_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_jax/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 6.573937266667296, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_jax/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_jax_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_jax/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.799182440000004, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_jax/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_jax_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_reference/alma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 6.520812733334121, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_reference/alma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_reference_breakdown_alma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/pixelization_numba_reference/sma:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.4727191899997706, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/pixelization_numba_reference/sma", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/pixelization_numba_reference_breakdown_sma_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/delaunay/sma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 1.210679142101435, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/delaunay/sma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/delaunay_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/delaunay/sma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.03261421409988543, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/delaunay/sma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/delaunay/sma:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.032107910299964716, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/delaunay/sma", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/delaunay_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/delaunay_numba/sma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.27887675409376816, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/delaunay_numba/sma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/delaunay_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/mge/sma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.8545848549001676, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/mge/sma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/mge_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/pixelization/sma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.9828833111998392, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/pixelization/sma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/pixelization_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/pixelization/sma:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.028076689298904965, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/pixelization/sma", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/pixelization_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/pixelization/sma:hpc_a100_mp@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.028550999599974602, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/pixelization/sma", + "config": "hpc_a100_mp", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/pixelization_hpc_a100_mp.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sma/pixelization_numba/sma:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.8240905327302723, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "interferometer/sma/pixelization_numba/sma", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/interferometer/sma/pixelization_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:point_source_image/image_plane/simple:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.06268672000005601, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "point_source_image/image_plane/simple", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/point_source_image/image_plane_local_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:point_source_image/image_plane/simple:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.02468953179195523, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "point_source_image/image_plane/simple", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-compute-10-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/point_source_image/image_plane_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:point_source_source/source_plane/simple:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0004377999994176207, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "point_source_source/source_plane/simple", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/point_source_source/source_plane_local_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:point_source_source/source_plane/simple:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0001464515007683076, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "point_source_source/source_plane/simple", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-compute-10-2", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/point_source_source/source_plane_hpc_ral_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:point_source_source/source_plane/simple:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.00022172799799591303, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "point_source_source/source_plane/simple", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-1", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/point_source_source/source_plane_hpc_a100_fp64.json", + "fragment": null + } + } + ], + "comparisons": [ + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.27, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/jwst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/jwst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/jwst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/jwst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay_nn/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay_nn/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay_numba/euclid:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay_numba/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/ao:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/ao:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.671, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/mge/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/hst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/hst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/jwst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/jwst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/jwst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge/jwst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/mge_mass_jax/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.232, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/jwst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/jwst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/jwst:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/jwst:local_cpu_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization_numba/euclid:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization_numba/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization_numba_mge_mass/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/delaunay/alma:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/delaunay/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/delaunay/sma:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/mge/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/mge/sma:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/pixelization/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:interferometer/pixelization/sma:local_cpu_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:point_source_image/image_plane_solved:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:point_source_source/source_plane_solved:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "runtime:point_source_source/source_plane_solved:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:cluster/image_plane:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.23.1", + "candidate": "2026.8.17.1", + "ratio": 0.469, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:cluster/image_plane:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:cluster/source_plane:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.7.23.1", + "ratio": 1.469, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:datacube/delaunay/alma_high:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:datacube/delaunay/alma_high:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.331, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.5.29.4", + "candidate": "2026.7.6.649", + "ratio": 1.108, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay/hst:hpc_a100_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay_nn/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay_nn/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay_numba/euclid:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/delaunay_numba/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/mge/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.225, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:imaging/mge/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.393, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.5.29.4", + "candidate": "2026.7.6.649", + "ratio": 1.139, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization/hst:hpc_a100_mp_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization_numba/euclid:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:imaging/pixelization_numba/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/delaunay/alma_high:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/delaunay_numba/alma_high:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/mge/alma_high:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/pixelization/alma_high:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/alma_high/pixelization_numba/alma_high:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay/alma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay/alma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay/alma:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba/alma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_direct_conv/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_direct_conv/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_jax/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_jax/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_reference/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_reference/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_source_loop/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_symmetric/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/delaunay_numba_two_stage/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/delaunay/jvla:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/mge/jvla:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/jvla/pixelization/jvla:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/alma:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/alma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/alma:hpc_a100_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/alma_high:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge/sma:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/mge_dft/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization/alma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization/alma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization/alma:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba/alma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_direct_conv/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_direct_conv/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_jax/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_jax/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_reference/alma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/pixelization_numba_reference/sma:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/delaunay/sma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/delaunay/sma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/delaunay/sma:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/delaunay_numba/sma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/mge/sma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/pixelization/sma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/pixelization/sma:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/pixelization/sma:hpc_a100_mp", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:interferometer/sma/pixelization_numba/sma:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:point_source_image/image_plane/simple:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:point_source_image/image_plane/simple:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:point_source_source/source_plane/simple:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:point_source_source/source_plane/simple:hpc_ral_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + }, + { + "comparison_key": "breakdown:point_source_source/source_plane/simple:hpc_a100_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + } + ], + "limitations": [ + "runtime axis only: compile times, VRAM and per-step component timings are not in this feed", + "evidence_updated_at is the newest release date encoded in a measured library version; result rows do not record measurement wall-clock time", + "valid_until is null: this project declares no freshness policy for release trends", + "vmap_per_call_s is null where a row carries no vmap block", + "rows without a device.provenance block (pre-autolens_profiling#342) are unqualified", + "6 row(s) above the load-average cap 8 are listed under coverage.excluded and never enter records" + ] + } +} diff --git a/state.json b/state.json new file mode 100644 index 0000000..00a160d --- /dev/null +++ b/state.json @@ -0,0 +1,35 @@ +{ + "schema_version": 1, + "organ": "pulse", + "repo": "PyAutoPulse", + "status": "yellow", + "headline": "1 project · 159 records · 0 cached", + "updated": "2026-10-02T12:03:46Z", + "pages_url": "https://pyautolabs.github.io/PyAutoPulse/", + "items": [ + { + "id": "pulse:lens:unqualified", + "severity": "yellow", + "state": "unknown", + "text": "lens: 157 of 159 records unqualified (producer provenance flags)", + "url": "https://pyautolabs.github.io/autolens_profiling/", + "prompt": null, + "actions": [ + { + "id": "open", + "label": "Open the project dashboard", + "kind": "link", + "target": "https://pyautolabs.github.io/autolens_profiling/", + "safety": "read_only" + } + ] + }, + { + "id": "pulse:lens:census", + "severity": "info", + "text": "lens: 159 records · 145 comparisons · 6 limitations · 2 qualified", + "url": "https://pyautolabs.github.io/autolens_profiling/", + "prompt": null + } + ] +} diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5a07156 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,163 @@ +"""Hermetic fixtures: a fabricated body map, registry and GitHub, no network.""" + +import json +import sys +import urllib.request +from pathlib import Path + +import pytest +import yaml + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +FIXTURES = Path(__file__).resolve().parent / "fixtures" +SHA_A = "a" * 40 +SHA_B = "b" * 40 +SHA_G = "c" * 40 + +LENS_ROW = { + "instance": "lens", + "repo": "autolens_profiling", + "summary_path": "dashboard/summary.json", + "supported_schema": "profiling-summary@1", + "dashboard_url": "https://pyautolabs.github.io/autolens_profiling/", + "library_refs": ["PyAutoLens", "PyAutoFit"], + "cortex_project": None, +} +SECOND_ROW = { + "instance": "galaxy", + "repo": "autogalaxy_profiling", + "summary_path": "out/profiling_summary.json", + "supported_schema": "profiling-summary@1", + "dashboard_url": "https://example.invalid/autogalaxy_profiling/", + "library_refs": ["PyAutoGalaxy"], + "cortex_project": None, +} +BODY_MAP = { + "repos": { + "autolens_profiling": { + "path": "lens/autolens_profiling", + "github": "PyAutoLabs/autolens_profiling", + "category": "project", + }, + "autogalaxy_profiling": { + "path": "galaxy/autogalaxy_profiling", + "github": "PyAutoLabs/autogalaxy_profiling", + "category": "project", + }, + "PyAutoLens": {"path": "lens/PyAutoLens", "github": "PyAutoLabs/PyAutoLens"}, + "PyAutoGalaxy": {"path": "galaxy/PyAutoGalaxy", "github": "PyAutoLabs/PyAutoGalaxy"}, + "PyAutoFit": {"path": "fit/PyAutoFit", "github": "PyAutoLabs/PyAutoFit"}, + } +} + + +def fixture_doc(name: str) -> dict: + return json.loads((FIXTURES / name).read_text()) + + +@pytest.fixture(autouse=True) +def no_network(monkeypatch): + """No test may reach the network; tests that need GitHub use ``web``.""" + + def refuse(request, *a, **k): + url = getattr(request, "full_url", request) + raise OSError(f"network disabled in tests: {url}") + + monkeypatch.setattr(urllib.request, "urlopen", refuse) + + +@pytest.fixture(autouse=True) +def isolated_env(monkeypatch, tmp_path): + """No test resolves the real PyAutoMind or a token from the shell.""" + monkeypatch.delenv("PYAUTO_MIND", raising=False) + monkeypatch.delenv("GH_TOKEN", raising=False) + monkeypatch.setenv("PYAUTO_ROOT", str(tmp_path / "no-workspace-here")) + + +@pytest.fixture +def fake_mind(tmp_path): + """A fabricated PyAutoMind checkout holding a minimal repos.yaml.""" + root = tmp_path / "PyAutoMind" + root.mkdir() + (root / "repos.yaml").write_text(yaml.safe_dump(BODY_MAP)) + return root + + +@pytest.fixture +def body_map(): + return {k: dict(v) for k, v in BODY_MAP["repos"].items()} + + +@pytest.fixture +def registry_file(tmp_path): + path = tmp_path / "registry.yaml" + path.write_text(yaml.safe_dump({"schema": 1, "instances": [dict(LENS_ROW)]})) + return path + + +@pytest.fixture +def two_registry_file(tmp_path): + path = tmp_path / "registry2.yaml" + path.write_text(yaml.safe_dump({"schema": 1, "instances": [dict(LENS_ROW), dict(SECOND_ROW)]})) + return path + + +class _Response: + def __init__(self, body: bytes): + self._body = body + + def read(self): + return self._body + + def __enter__(self): + return self + + def __exit__(self, *exc): + return False + + +class FakeGitHub: + """Serves the commits API and raw files from a dict; logs every request. + + ``branches[github] = sha`` answers the commits API; ``files[(github, sha, + path)] = bytes`` answers raw.githubusercontent.com. ``down = True`` makes + every request fail like a dropped connection. + """ + + def __init__(self): + self.branches: dict[str, str] = {} + self.files: dict[tuple[str, str, str], bytes] = {} + self.requests: list = [] + self.down = False + + def publish(self, github, sha, path, doc): + self.branches[github] = sha + body = doc if isinstance(doc, bytes) else json.dumps(doc).encode() + self.files[(github, sha, path)] = body + + def __call__(self, request, timeout=None): + url = request.full_url + self.requests.append(request) + if self.down: + raise OSError("connection reset by peer") + api = "https://api.github.com/repos/" + raw = "https://raw.githubusercontent.com/" + if url.startswith(api): + rest = url[len(api) :] + github, _, branch = rest.partition("/commits/") + if github in self.branches: + return _Response(json.dumps({"sha": self.branches[github]}).encode()) + elif url.startswith(raw): + owner, repo, sha, path = url[len(raw) :].split("/", 3) + body = self.files.get((f"{owner}/{repo}", sha, path)) + if body is not None: + return _Response(body) + raise OSError(f"404 {url}") + + +@pytest.fixture +def web(monkeypatch): + fake = FakeGitHub() + monkeypatch.setattr(urllib.request, "urlopen", fake) + return fake diff --git a/tests/fixtures/axis_mismatch.json b/tests/fixtures/axis_mismatch.json new file mode 100644 index 0000000..5dd8c01 --- /dev/null +++ b/tests/fixtures/axis_mismatch.json @@ -0,0 +1,121 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 1, + "points": 2, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "compile:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "compile", + "unit": "s", + "measurement": { + "single_jit_s": 12.0, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "compile:imaging/mge:local_cpu_fp64@1.1.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.4, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.1.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + } + ], + "comparisons": [ + { + "comparison_key": "compile:imaging/mge:local_cpu_fp64", + "policy": "fixture-policy", + "axis": "compile", + "metric": "single_jit_s", + "baseline": "1.0.0", + "candidate": "1.1.0", + "ratio": 0.033, + "status": "improved", + "qualified": true, + "reasons": [] + } + ], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/fixtures/changed_hardware.json b/tests/fixtures/changed_hardware.json new file mode 100644 index 0000000..27f0b4e --- /dev/null +++ b/tests/fixtures/changed_hardware.json @@ -0,0 +1,285 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 3, + "points": 6, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.1.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.55, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.1.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge:a100_fp32@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.01, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "a100_fp32", + "sparse": false, + "tier": "local", + "device": "a100", + "backend": "gpu", + "precision": "float32", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "gpu-1", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "a100_fp32" + } + }, + { + "id": "runtime:imaging/mge:a100_fp32@1.1.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.012, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "a100_fp32", + "sparse": false, + "tier": "local", + "device": "a100", + "backend": "gpu", + "precision": "float32", + "library": "PyAutoLens", + "library_version": "1.1.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "gpu-1", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "a100_fp32" + } + }, + { + "id": "runtime:imaging/mge:mixed@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "mixed", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "mixed" + } + }, + { + "id": "runtime:imaging/mge:mixed@1.1.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.01, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "mixed", + "sparse": false, + "tier": "local", + "device": "a100", + "backend": "gpu", + "precision": "float32", + "library": "PyAutoLens", + "library_version": "1.1.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "gpu-1", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "mixed" + } + } + ], + "comparisons": [ + { + "comparison_key": "runtime:imaging/mge:local_cpu_fp64", + "policy": "fixture-policy", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "1.0.0", + "candidate": "1.1.0", + "ratio": 1.1, + "status": "flat", + "qualified": true, + "reasons": [] + }, + { + "comparison_key": "runtime:imaging/mge:a100_fp32", + "policy": "fixture-policy", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "1.0.0", + "candidate": "1.1.0", + "ratio": 1.2, + "status": "flat", + "qualified": true, + "reasons": [] + }, + { + "comparison_key": "runtime:imaging/mge:mixed", + "policy": "fixture-policy", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "1.0.0", + "candidate": "1.1.0", + "ratio": 0.02, + "status": "improved", + "qualified": true, + "reasons": [] + } + ], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/fixtures/duplicate_id.json b/tests/fixtures/duplicate_id.json new file mode 100644 index 0000000..107244f --- /dev/null +++ b/tests/fixtures/duplicate_id.json @@ -0,0 +1,108 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 0, + "points": 2, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.6, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + } + ], + "comparisons": [], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/fixtures/lens_summary_v1.json b/tests/fixtures/lens_summary_v1.json new file mode 100644 index 0000000..8999c1b --- /dev/null +++ b/tests/fixtures/lens_summary_v1.json @@ -0,0 +1,526 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "autolens_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T19:43:00Z", + "evidence_updated_at": "2026-08-17T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "227b5c919b1c205962427a6f48fe233770220a69", + "comparison_policy": { + "id": "runtime-drift-2x-1ms", + "ratio": 2.0, + "floor_s": 0.001, + "reference_host": "euclid-ral-gpu-2", + "loadavg_cap": 8.0 + }, + "coverage": { + "expected": { + "sections": [ + "runtime", + "breakdown", + "simulators", + "lens" + ], + "cells": null, + "reason": "no declared cell matrix; the results/ scan is the inventory" + }, + "observed": { + "series": 5, + "points": 11, + "releases": 3, + "cells": 5 + }, + "excluded": [ + { + "id": "breakdown:interferometer/sdp81/delaunay/sdp81:hpc_a100_fp64@2026.8.17.1", + "reason": "loadavg 65.7 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/delaunay_hpc_a100_fp64.json", + "fragment": null + } + }, + { + "id": "breakdown:interferometer/sdp81/delaunay_numba/sdp81:hpc_ral_cpu_fp64@2026.8.17.1", + "reason": "loadavg 68.3 above the cap 8", + "evidence": { + "path": "results/breakdown/interferometer/sdp81/delaunay_numba_hpc_ral_cpu_fp64.json", + "fragment": null + } + } + ] + }, + "records": [ + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 16.729484930000034, + "vmap_per_call_s": 12.66077735333335 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.523518409999815, + "vmap_per_call_s": 3.774630096666685 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/delaunay_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.11771118000033312, + "vmap_per_call_s": 0.1651308966667178 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.07903557000008732, + "vmap_per_call_s": 0.11596217666665325 + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/mge/mge_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_fp64@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 13.724898559999565, + "vmap_per_call_s": 12.49813459666669 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/hst/comparison.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/pixelization/hst:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 3.1860993599999348, + "vmap_per_call_s": 4.622900409999965 + }, + "identity": { + "section": "runtime", + "cell": "imaging/pixelization/hst", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/pixelization/pixelization_likelihood_summary_hst_v2026.8.17.1.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/image_plane:local_cpu_fp64@2026.7.23.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 10.24726366665709, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.23.1", + "release_date": "2026-07-23", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_breakdown_v2026.7.23.1.json", + "fragment": null + } + }, + { + "id": "breakdown:cluster/image_plane:local_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.809658799998337, + "vmap_per_call_s": null + }, + "identity": { + "section": "breakdown", + "cell": "cluster/image_plane", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "DESKTOP-H143S82", + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/breakdown/cluster/image_plane_local_cpu_fp64.json", + "fragment": null + } + }, + { + "id": "runtime:imaging/delaunay/hst:local_cpu_fp64_sparse@2026.7.6.649", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 4.144032109999898, + "vmap_per_call_s": 5.215584503333351 + }, + "identity": { + "section": "runtime", + "cell": "imaging/delaunay/hst", + "config": "local_cpu_fp64", + "sparse": true, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.7.6.649", + "release_date": "2026-07-06", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block (pre-#342 row)" + }, + "evidence": { + "path": "results/runtime/imaging/delaunay/hst/comparison.json", + "fragment": "local_cpu_fp64_sparse" + } + }, + { + "id": "runtime:point_source_source/source_plane_solved:hpc_ral_cpu_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.00025833239778876304, + "vmap_per_call_s": 9.664240060374141e-05 + }, + "identity": { + "section": "runtime", + "cell": "point_source_source/source_plane_solved", + "config": "hpc_ral_cpu_fp64", + "sparse": false, + "tier": "hpc", + "device": "ral_cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": "366911", + "loadavg": 0.16, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/runtime/point_source_source/source_plane_solved/comparison.json", + "fragment": "hpc_ral_cpu_fp64" + } + }, + { + "id": "runtime:point_source_source/source_plane_solved:hpc_a100_fp64@2026.8.17.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0006424111023079603, + "vmap_per_call_s": 5.645434339385247e-06 + }, + "identity": { + "section": "runtime", + "cell": "point_source_source/source_plane_solved", + "config": "hpc_a100_fp64", + "sparse": false, + "tier": "hpc", + "device": "a100", + "backend": "gpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "2026.8.17.1", + "release_date": "2026-08-17", + "reason": null + }, + "provenance": { + "host": "euclid-ral-gpu-2", + "job": "366912", + "loadavg": 1.16, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/runtime/point_source_source/source_plane_solved/comparison.json", + "fragment": "hpc_a100_fp64" + } + } + ], + "comparisons": [ + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.27, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/mge/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.671, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/pixelization/hst:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.6.649", + "candidate": "2026.8.17.1", + "ratio": 0.232, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "breakdown:cluster/image_plane:local_cpu_fp64", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.7.23.1", + "candidate": "2026.8.17.1", + "ratio": 0.469, + "status": "improved", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block (pre-#342 row)", + "candidate row unqualified: no provenance block (pre-#342 row)" + ] + }, + { + "comparison_key": "runtime:imaging/delaunay/hst:local_cpu_fp64_sparse", + "policy": "runtime-drift-2x-1ms", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": null, + "candidate": null, + "ratio": null, + "status": "insufficient", + "qualified": false, + "reasons": [ + "one release only" + ] + } + ], + "limitations": [ + "runtime axis only: compile times, VRAM and per-step component timings are not in this feed", + "evidence_updated_at is the newest release date encoded in a measured library version; result rows do not record measurement wall-clock time", + "valid_until is null: this project declares no freshness policy for release trends", + "vmap_per_call_s is null where a row carries no vmap block", + "rows without a device.provenance block (pre-autolens_profiling#342) are unqualified", + "6 row(s) above the load-average cap 8 are listed under coverage.excluded and never enter records" + ], + "fixture_note": "trimmed copy of autolens_profiling dashboard/summary.json at d9f385f002803b822a6293d7bd20113d2611dca1 (producer_revision 227b5c91)" +} diff --git a/tests/fixtures/second_producer.json b/tests/fixtures/second_producer.json new file mode 100644 index 0000000..742223d --- /dev/null +++ b/tests/fixtures/second_producer.json @@ -0,0 +1,121 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "autogalaxy_profiling_fixture", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 1, + "points": 2, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "ellipse:hst/ellipse_fit/x7:gpu_mp@2026.9.1.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.002, + "vmap_per_call_s": null + }, + "identity": { + "section": "ellipse", + "cell": "hst/ellipse_fit/x7", + "config": "gpu_mp", + "sparse": false, + "tier": "local", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.9.1.1", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "gpu-2", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/ellipse/hst_x7.json", + "fragment": "gpu_mp" + } + }, + { + "id": "ellipse:hst/ellipse_fit/x7:gpu_mp@2026.9.27.1", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.0051, + "vmap_per_call_s": null + }, + "identity": { + "section": "ellipse", + "cell": "hst/ellipse_fit/x7", + "config": "gpu_mp", + "sparse": false, + "tier": "local", + "device": "a100", + "backend": "gpu", + "precision": "mixed", + "library": "PyAutoLens", + "library_version": "2026.9.27.1", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "gpu-2", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/ellipse/hst_x7.json", + "fragment": "gpu_mp" + } + } + ], + "comparisons": [ + { + "comparison_key": "ellipse:hst/ellipse_fit/x7:gpu_mp", + "policy": "fixture-policy", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "2026.9.1.1", + "candidate": "2026.9.27.1", + "ratio": 2.55, + "status": "drifted", + "qualified": true, + "reasons": [] + } + ], + "limitations": [ + "second-producer fixture: a different section/cell grammar behind the same profiling-summary@1 contract" + ] +} diff --git a/tests/fixtures/unknown_provenance.json b/tests/fixtures/unknown_provenance.json new file mode 100644 index 0000000..add03bd --- /dev/null +++ b/tests/fixtures/unknown_provenance.json @@ -0,0 +1,123 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 1, + "points": 2, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": null, + "job": null, + "loadavg": null, + "has_provenance": false, + "qualified": false, + "reason": "no provenance block" + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + }, + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.1.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.1.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + } + ], + "comparisons": [ + { + "comparison_key": "runtime:imaging/mge:local_cpu_fp64", + "policy": "fixture-policy", + "axis": "runtime", + "metric": "single_jit_s", + "baseline": "1.0.0", + "candidate": "1.1.0", + "ratio": 1.0, + "status": "flat", + "qualified": false, + "reasons": [ + "baseline row unqualified: no provenance block" + ] + } + ], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/fixtures/unsupported_schema.json b/tests/fixtures/unsupported_schema.json new file mode 100644 index 0000000..0fbe8de --- /dev/null +++ b/tests/fixtures/unsupported_schema.json @@ -0,0 +1,73 @@ +{ + "schema": "profiling-summary", + "version": 2, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": "2026-09-01T00:00:00Z", + "evidence_updated_at_reason": null, + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 0, + "points": 1, + "releases": 2, + "cells": 1 + }, + "excluded": [] + }, + "records": [ + { + "id": "runtime:imaging/mge:local_cpu_fp64@1.0.0", + "axis": "runtime", + "unit": "s", + "measurement": { + "single_jit_s": 0.5, + "vmap_per_call_s": null + }, + "identity": { + "section": "runtime", + "cell": "imaging/mge", + "config": "local_cpu_fp64", + "sparse": false, + "tier": "local", + "device": "cpu", + "backend": "cpu", + "precision": "float64", + "library": "PyAutoLens", + "library_version": "1.0.0", + "release_date": "2026-09-01", + "reason": null + }, + "provenance": { + "host": "host-a", + "job": null, + "loadavg": 0.5, + "has_provenance": true, + "qualified": true, + "reason": null + }, + "evidence": { + "path": "results/a.json", + "fragment": "local_cpu_fp64" + } + } + ], + "comparisons": [], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/fixtures/valid_empty.json b/tests/fixtures/valid_empty.json new file mode 100644 index 0000000..e4e21b5 --- /dev/null +++ b/tests/fixtures/valid_empty.json @@ -0,0 +1,37 @@ +{ + "schema": "profiling-summary", + "version": 1, + "project": "fixture_profiling", + "scope": "release-runtime", + "generated_at": "2026-09-30T12:00:00Z", + "evidence_updated_at": null, + "evidence_updated_at_reason": "no rows measured yet", + "valid_until": null, + "producer_revision": "0123456789abcdef0123456789abcdef01234567", + "comparison_policy": { + "id": "fixture-policy", + "ratio": 2.0, + "floor_s": 0.001 + }, + "coverage": { + "expected": { + "sections": [ + "runtime" + ], + "cells": null, + "reason": "fixture" + }, + "observed": { + "series": 0, + "points": 0, + "releases": 0, + "cells": 0 + }, + "excluded": [] + }, + "records": [], + "comparisons": [], + "limitations": [ + "fixture: hand-written to exercise one reader acceptance case" + ] +} diff --git a/tests/test_board.py b/tests/test_board.py new file mode 100644 index 0000000..8859891 --- /dev/null +++ b/tests/test_board.py @@ -0,0 +1,197 @@ +"""The board: three notions, producer comparisons verbatim, cached semantics, state.json.""" + +import json + +import pytest +from conftest import SHA_A, SHA_G, fixture_doc + +from pulse import board, cli, ingest, registry + +GH = "PyAutoLabs/autolens_profiling" +PATH = "dashboard/summary.json" +NOW = "2026-10-02T00:00:00Z" + + +@pytest.fixture +def lens(registry_file, fake_mind): + return registry.get(registry.load(registry_file, mind=fake_mind), "lens") + + +def _view(lens, web, tmp_path, fixture, now=NOW): + web.publish(GH, SHA_A, PATH, fixture_doc(fixture)) + return ingest.ingest(lens, tmp_path, now=now) + + +def _validator(): + mod = cli._state_validator() + if mod is None: + pytest.skip("no PyAutoBrain checkout here to validate state.json") + return mod + + +def test_the_three_notions_are_separate_columns(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "lens_summary_v1.json") + md = board.render_markdown([s], NOW) + assert "| Integrity | Freshness | Qualification |" in md + assert board.integrity(s) == "ok" + assert board.freshness(s, NOW) == "freshness policy unspecified · age 46 d at fetch 2026-10-02" + assert board.qualification(s).endswith("comparisons qualified") + + +def test_valid_empty_feed_says_no_measurements(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "valid_empty.json") + md = board.render_markdown([s], NOW) + assert "**No measurements.**" in md and "no measurements" in board.coverage(s) + assert "all measurements passed" not in md.replace('"all measurements passed"', "") + state = board.render_state([s], NOW, NOW) + assert state["status"] == "yellow" + assert any(i["text"].endswith("no measurements (a valid, empty feed)") for i in state["items"]) + + +def test_cached_snapshot_is_labelled_and_never_re_aged(lens, web, tmp_path): + _view(lens, web, tmp_path, "lens_summary_v1.json") + web.down = True + first = ingest.ingest(lens, tmp_path, now="2026-10-05T00:00:00Z") + board.write([first], tmp_path, now="2026-10-05T00:00:00Z") + md1 = (tmp_path / "dashboard.md").read_text() + state1 = json.loads((tmp_path / "state.json").read_text()) + second = ingest.ingest(lens, tmp_path, now="2026-10-06T00:00:00Z") + board.write([second], tmp_path, now="2026-10-06T00:00:00Z") + md2 = (tmp_path / "dashboard.md").read_text() + assert "**Cached:**" in md2 and "fetched 2026-10-02T00:00:00Z" in md2 + assert "evidence 2026-08-17" in md2 and "connection reset" in md2 + assert md1 == md2 # the second render re-aged nothing + assert json.loads((tmp_path / "state.json").read_text())["updated"] == state1["updated"] + assert board.integrity(second) == "cached · latest fetch unavailable" + (cached,) = [i for i in state1["items"] if i["id"] == "pulse:lens:cached"] + assert cached["severity"] == "yellow" + + +def test_failed_without_a_snapshot_is_red(lens, tmp_path): + s = ingest.ingest(lens, tmp_path, now=NOW) + state = board.render_state([s], NOW, NOW) + assert state["status"] == "red" + assert state["items"][0]["text"] == "lens: summary unavailable" + assert "Unavailable:" in board.render_markdown([s], NOW) + + +def test_unsupported_is_red_even_with_a_cache(lens, web, tmp_path): + _view(lens, web, tmp_path, "lens_summary_v1.json") + s = _view(lens, web, tmp_path, "unsupported_schema.json") + state = board.render_state([s], NOW, NOW) + assert state["status"] == "red" and "unsupported" in state["items"][0]["text"] + + +def test_unknown_provenance_shows_unqualified_and_counts(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "unknown_provenance.json") + assert board.qualification(s) == "1/2 records · 0/1 comparisons qualified" + state = board.render_state([s], NOW, NOW) + assert any(i["id"] == "pulse:lens:unqualified" for i in state["items"]) + + +def test_refused_pairs_show_the_reason_and_no_ratio(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "axis_mismatch.json") + md = board.render_markdown([s], NOW) + assert "lens / refused by the reader (never combined)" in md + assert "not shown (refused)" in md and "0.033" not in md + assert "axis mismatch" in md + + +def test_changed_hardware_renders_separate_groups(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "changed_hardware.json") + md = board.render_markdown([s], NOW) + assert "### lens / comparisons on cpu · cpu · float64" in md + assert "### lens / comparisons on a100 · gpu · float32" in md + assert "hardware identity changed" in md + + +def test_ratios_are_the_producers_never_recomputed(lens, web, tmp_path): + doc = fixture_doc("second_producer.json") + doc["comparisons"][0]["ratio"] = 7.25 # deliberately not candidate/baseline + web.publish(GH, SHA_A, PATH, doc) + s = ingest.ingest(lens, tmp_path, now=NOW) + md = board.render_markdown([s], NOW) + assert "| 7.25 |" in md and "2.55" not in md + + +def test_drift_item_hands_off_to_profiling_triage(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "second_producer.json") + state = board.render_state([s], NOW, NOW) + key = "ellipse:hst/ellipse_fit/x7:gpu_mp" + (item,) = [i for i in state["items"] if i["id"] == f"pulse:lens:drift:{key}"] + assert item["severity"] == "yellow" and item["prompt"] == f"/profiling triage {key}" + triage = item["actions"][0] + assert triage == { + "id": "triage", + "label": "Hand off to profiling triage", + "kind": "prompt", + "target": f"/profiling triage {key}", + "safety": "scientific_judgement", + } + assert item["actions"][1]["target"].startswith(f"https://github.com/{GH}/blob/{SHA_A}/") + assert _validator().validate_state(state) == [] + + +def test_unqualified_drift_is_a_contextual_info_flag(lens, web, tmp_path): + doc = fixture_doc("second_producer.json") + doc["comparisons"][0]["qualified"] = False + web.publish(GH, SHA_A, PATH, doc) + state = board.render_state([ingest.ingest(lens, tmp_path, now=NOW)], NOW, NOW) + (item,) = [i for i in state["items"] if ":drift:" in i["id"]] + assert item["severity"] == "info" and "contextual flag" in item["text"] + + +def test_no_freshness_policy_past_the_presentation_window_is_called_out(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "lens_summary_v1.json") + state = board.render_state([s], NOW, "2027-01-01T00:00:00Z") + assert any(i["id"] == "pulse:lens:aged" for i in state["items"]) + assert not any(i["id"] == "pulse:lens:aged" for i in board.render_state([s], NOW, NOW)["items"]) + + +def test_an_expired_valid_until_is_stale(lens, web, tmp_path): + doc = fixture_doc("unknown_provenance.json") + doc["valid_until"] = "2026-09-15T00:00:00Z" + web.publish(GH, SHA_A, PATH, doc) + s = ingest.ingest(lens, tmp_path, now=NOW) + assert board.freshness(s, NOW).startswith("stale") + assert any(i["id"] == "pulse:lens:stale" for i in board.render_state([s], NOW, NOW)["items"]) + + +def test_second_producer_renders_as_a_second_row_with_no_branching( + two_registry_file, fake_mind, web, tmp_path +): + instances = registry.load(two_registry_file, mind=fake_mind) + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + web.publish( + "PyAutoLabs/autogalaxy_profiling", + SHA_G, + "out/profiling_summary.json", + fixture_doc("second_producer.json"), + ) + views = [ingest.ingest(i, tmp_path, now=NOW) for i in instances] + md = board.render_markdown(views, NOW) + assert "| [lens](#lens) (autolens_profiling) |" in md + assert "| [galaxy](#galaxy) (autogalaxy_profiling) |" in md + assert board.headline(views) == "2 projects · 13 records · 0 cached" + assert set(board.markers(md)) == {"lens", "galaxy"} + state = board.render_state(views, NOW, NOW) + assert state["organ"] == "pulse" and state["repo"] == "PyAutoPulse" + assert state["pages_url"] == "https://pyautolabs.github.io/PyAutoPulse/" + assert _validator().validate_state(state) == [] + + +def test_render_is_deterministic(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "lens_summary_v1.json") + board.write([s], tmp_path, now=NOW) + first = {p.name: p.read_bytes() for p in tmp_path.glob("*.*") if p.is_file()} + board.write([ingest.ingest(lens, tmp_path, now="2026-10-03T00:00:00Z")], tmp_path, now=NOW) + assert {p.name: p.read_bytes() for p in tmp_path.glob("*.*") if p.is_file()} == first + + +def test_no_league_table_across_projects(lens, web, tmp_path): + s = _view(lens, web, tmp_path, "lens_summary_v1.json") + md = board.render_markdown([s], NOW).lower() + for word in ("fastest", "slowest", "league table", "winner", "verdict:", "release-ready"): + assert word not in md + html = board.render_html([s], NOW) + assert "PyAutoPulse dashboard" in html and "data-age-from=" in html diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..391999b --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,99 @@ +"""bin/pyauto-pulse: check, board, census, fetch.""" + +import json + +import pytest +from conftest import SHA_A, SHA_B, fixture_doc + +from pulse import cli + +GH = "PyAutoLabs/autolens_profiling" +PATH = "dashboard/summary.json" + + +@pytest.fixture +def argv(registry_file, fake_mind, tmp_path): + out = tmp_path / "organ" + out.mkdir() + + def make(cmd, *extra): + return [ + "--registry", + str(registry_file), + cmd, + "--mind", + str(fake_mind), + "--out", + str(out), + *extra, + ] + + make.out = out + return make + + +def test_board_then_check_online_and_offline(argv, web, capsys): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + assert cli.main(argv("board")) == 0 + for name in ("dashboard.md", "dashboard.html", "badge.json", "state.json"): + assert (argv.out / name).is_file() + assert (argv.out / "receipts" / "lens.json").is_file() + assert (argv.out / "snapshots" / "lens.json").is_file() + capsys.readouterr() + assert cli.main(argv("check")) == 0 + assert capsys.readouterr().out.rstrip().endswith("check: OK") + web.down = True + assert cli.main(argv("check", "--offline")) == 0 + assert "check: OK" in capsys.readouterr().out + + +def test_state_json_passes_the_brain_validator(argv, web): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + cli.main(argv("board")) + validator = cli._state_validator() + if validator is None: + pytest.skip("no PyAutoBrain checkout here") + state = json.loads((argv.out / "state.json").read_text()) + assert validator.validate_state(state) == [] + assert json.loads((argv.out / "badge.json").read_text())["label"] == "pulse" + + +def test_check_fails_when_the_dashboard_is_behind_the_receipt(argv, web, capsys): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + cli.main(argv("board")) + web.publish(GH, SHA_B, PATH, fixture_doc("lens_summary_v1.json")) + capsys.readouterr() + assert cli.main(argv("check")) == 1 + out = capsys.readouterr().out + assert "FAIL dashboard: stale for lens" in out and out.rstrip().endswith("check: FAIL") + + +def test_check_fails_on_an_unavailable_feed_with_no_capture(argv, capsys): + assert cli.main(argv("check")) == 1 + assert "FAIL lens: unavailable" in capsys.readouterr().out + + +def test_census_and_fetch(argv, web, capsys): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + assert cli.main(argv("fetch", "--instance", "lens")) == 0 + assert f"lens: ok at {SHA_A[:12]}" in capsys.readouterr().out + assert not (argv.out / "dashboard.md").exists() # fetch renders nothing + web.down = True + assert cli.main(argv("census")) == 0 + line = capsys.readouterr().out.strip() + assert line.startswith("lens: 11 records · 5 comparisons · 6 limitations ·") + assert cli.main(argv("fetch")) == 1 + + +def test_board_from_a_local_file_is_labelled_local(argv, tmp_path, capsys): + path = tmp_path / "summary.json" + path.write_text(json.dumps(fixture_doc("valid_empty.json"))) + assert cli.main(argv("board", "--from", f"lens={path}")) == 0 + md = (argv.out / "dashboard.md").read_text() + assert "**Local read:**" in md and "**No measurements.**" in md + assert not (argv.out / "receipts").exists() + + +def test_unknown_instance_is_a_clean_error(argv, capsys): + assert cli.main(argv("fetch", "--instance", "nope")) == 1 + assert "no instance 'nope'" in capsys.readouterr().err diff --git a/tests/test_ingest.py b/tests/test_ingest.py new file mode 100644 index 0000000..3f98687 --- /dev/null +++ b/tests/test_ingest.py @@ -0,0 +1,112 @@ +"""One-commit ingest, receipts, last-good snapshots and cached semantics.""" + +import json +import subprocess + +import pytest +from conftest import SHA_A, SHA_B, fixture_doc + +from pulse import ingest, registry + +GH = "PyAutoLabs/autolens_profiling" +PATH = "dashboard/summary.json" + + +@pytest.fixture +def lens(registry_file, fake_mind): + return registry.get(registry.load(registry_file, mind=fake_mind), "lens") + + +def test_ok_reads_the_file_at_the_resolved_commit(lens, web, tmp_path, monkeypatch): + monkeypatch.setenv("GH_TOKEN", "t0k") + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + s = ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + assert s.outcome == "ok" and not s.cached and s.commit == SHA_A + api, raw = (r.full_url for r in web.requests) + assert api == f"https://api.github.com/repos/{GH}/commits/main" + assert raw == f"https://raw.githubusercontent.com/{GH}/{SHA_A}/{PATH}" + assert web.requests[0].get_header("Authorization") == "Bearer t0k" + assert web.requests[1].get_header("Authorization") is None # the token never leaves the API + assert web.requests[0].get_header("User-agent") == ingest.USER_AGENT + receipt = ingest.read_receipt(tmp_path, "lens") + assert receipt["resolved_commit"] == SHA_A and receipt["outcome"] == "ok" + assert receipt["record_count"] == 11 and receipt["errors"] == [] + assert receipt["cached_from"] is None + snap = ingest.read_snapshot(tmp_path, "lens") + assert snap["commit"] == SHA_A and snap["fetched_at"] == "2026-10-02T00:00:00Z" + + +def test_unchanged_reingest_rewrites_nothing(lens, web, tmp_path): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + before = {p: p.read_bytes() for p in tmp_path.glob("*s/lens.json")} + ingest.ingest(lens, tmp_path, now="2026-10-03T00:00:00Z") + assert {p: p.read_bytes() for p in tmp_path.glob("*s/lens.json")} == before + web.publish(GH, SHA_B, PATH, fixture_doc("lens_summary_v1.json")) + s = ingest.ingest(lens, tmp_path, now="2026-10-04T00:00:00Z") + assert s.commit == SHA_B and s.fetched_at == "2026-10-04T00:00:00Z" + + +def test_unavailable_keeps_the_cached_snapshot_with_its_original_times(lens, web, tmp_path): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + good = ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + web.down = True + s = ingest.ingest(lens, tmp_path, now="2026-10-09T00:00:00Z") + assert s.outcome == "unavailable" and s.cached + assert s.commit == SHA_A and s.fetched_at == "2026-10-02T00:00:00Z" + assert s.doc["evidence_updated_at"] == good.doc["evidence_updated_at"] + assert "connection reset" in s.errors[0] + receipt = ingest.read_receipt(tmp_path, "lens") + assert receipt["outcome"] == "unavailable" and receipt["resolved_commit"] is None + assert receipt["fetched_at"] == "2026-10-09T00:00:00Z" + assert receipt["cached_from"] == "2026-10-02T00:00:00Z" + + +def test_unavailable_with_no_snapshot_has_nothing_to_show(lens, tmp_path): + s = ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") # no_network refuses + assert s.outcome == "unavailable" and s.doc is None and not s.cached + assert ingest.read_snapshot(tmp_path, "lens") is None + + +@pytest.mark.parametrize( + "fixture, outcome", + [("unsupported_schema.json", "unsupported"), ("duplicate_id.json", "invalid")], +) +def test_bad_feeds_fail_and_keep_the_last_good_snapshot(lens, web, tmp_path, fixture, outcome): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + web.publish(GH, SHA_B, PATH, fixture_doc(fixture)) + s = ingest.ingest(lens, tmp_path, now="2026-10-03T00:00:00Z") + assert s.outcome == outcome and s.cached + assert s.commit == SHA_A and s.attempt_commit == SHA_B + assert ingest.read_snapshot(tmp_path, "lens")["commit"] == SHA_A + + +def test_not_json_is_invalid(lens, web, tmp_path): + web.publish(GH, SHA_A, PATH, b"404") + s = ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + assert s.outcome == "invalid" and "not JSON" in s.errors[0] + + +def test_offline_reads_committed_files_and_writes_nothing(lens, web, tmp_path): + web.publish(GH, SHA_A, PATH, fixture_doc("lens_summary_v1.json")) + ingest.ingest(lens, tmp_path, now="2026-10-02T00:00:00Z") + web.requests.clear() + s = ingest.ingest(lens, tmp_path, offline=True) + assert s.outcome == "ok" and s.commit == SHA_A and web.requests == [] + + +def test_a_local_read_reports_revision_and_dirty_state_and_writes_nothing(lens, tmp_path): + checkout = tmp_path / "autolens_profiling" + (checkout / "dashboard").mkdir(parents=True) + (checkout / PATH).write_text(json.dumps(fixture_doc("valid_empty.json"))) + git = ["git", "-C", str(checkout), "-c", "user.email=t@t", "-c", "user.name=t"] + subprocess.run([*git, "init", "-q"], check=True) + subprocess.run([*git, "add", "."], check=True) + subprocess.run([*git, "commit", "-qm", "x"], check=True) + out = tmp_path / "organ" + s = ingest.ingest(lens, out, local_path=checkout) + assert s.source == "local" and s.dirty is False and len(s.commit) == 40 + (checkout / "scratch.txt").write_text("edit") + assert ingest.ingest(lens, out, local_path=checkout).dirty is True + assert not (out / "receipts").exists() and not (out / "snapshots").exists() diff --git a/tests/test_registry.py b/tests/test_registry.py new file mode 100644 index 0000000..96bf905 --- /dev/null +++ b/tests/test_registry.py @@ -0,0 +1,97 @@ +"""registry.yaml: schema, body-map resolution, disjoint scopes.""" + +import pytest +import yaml +from conftest import LENS_ROW, SECOND_ROW + +from pulse import ORGAN_ROOT, registry + + +def _doc(*rows): + return {"schema": 1, "instances": [dict(r) for r in rows]} + + +def test_the_committed_registry_is_valid_against_a_body_map(body_map): + data = yaml.safe_load((ORGAN_ROOT / "registry.yaml").read_text()) + body_map.update({"PyAutoArray": {"github": "PyAutoLabs/PyAutoArray"}}) + assert registry.validate(data, body_map) == [] + assert [r["instance"] for r in data["instances"]] == ["lens"] + + +def test_load_resolves_path_and_github_from_the_body_map(registry_file, fake_mind): + (inst,) = registry.load(registry_file, mind=fake_mind) + assert inst.github == "PyAutoLabs/autolens_profiling" + assert inst.path == "lens/autolens_profiling" + assert inst.schema_name == "profiling-summary" and inst.schema_version == 1 + assert inst.blob_url("f" * 40, "results/x.json").endswith( + "/blob/" + "f" * 40 + "/results/x.json" + ) + + +def test_a_registry_row_may_not_carry_its_own_path_or_github(body_map): + row = dict(LENS_ROW, path="lens/autolens_profiling", github="PyAutoLabs/autolens_profiling") + problems = registry.validate(_doc(row), body_map) + assert any("unknown field(s) github, path" in p for p in problems) + + +def test_repo_must_be_a_body_map_identity(body_map): + problems = registry.validate(_doc(dict(LENS_ROW, repo="nowhere_profiling")), body_map) + assert any("not in the body map" in p for p in problems) + problems = registry.validate(_doc(dict(LENS_ROW, library_refs=["PyAutoNope"])), body_map) + assert any("library_refs not in the body map: PyAutoNope" in p for p in problems) + + +def test_the_same_summary_cannot_be_registered_twice(body_map): + twin = dict(LENS_ROW, instance="lens2") + problems = registry.validate(_doc(LENS_ROW, twin), body_map) + assert any("already registered as 'lens'" in p for p in problems) + assert registry.validate(_doc(LENS_ROW, SECOND_ROW), body_map) == [] + + +@pytest.mark.parametrize( + "field, value, needle", + [ + ("summary_path", "../outside.json", "summary_path"), + ("summary_path", "/abs/summary.json", "summary_path"), + ("supported_schema", "profiling-summary", "supported_schema"), + ("dashboard_url", "http://insecure.invalid/", "dashboard_url"), + ("instance", "Lens", "instance must match"), + ], +) +def test_malformed_rows_are_refused(body_map, field, value, needle): + problems = registry.validate(_doc(dict(LENS_ROW, **{field: value})), body_map) + assert any(needle in p for p in problems), problems + + +def test_explicit_mind_wins_over_the_environment(tmp_path, fake_mind, monkeypatch): + elsewhere = tmp_path / "other" / "PyAutoMind" + elsewhere.mkdir(parents=True) + (elsewhere / "repos.yaml").write_text("repos: {}\n") + monkeypatch.setenv("PYAUTO_MIND", str(elsewhere)) + assert registry.body_map_path(fake_mind) == fake_mind / "repos.yaml" + assert registry.body_map_path() == elsewhere / "repos.yaml" + + +def test_pyauto_root_grouped_and_flat_layouts_resolve(tmp_path, monkeypatch): + monkeypatch.setattr(registry, "ORGAN_ROOT", tmp_path / "x" / "y" / "PyAutoPulse") + for layout in ("organs/PyAutoMind", "PyAutoMind"): + root = tmp_path / layout.replace("/", "_") + (root / layout).mkdir(parents=True) + (root / layout / "repos.yaml").write_text("repos: {}\n") + monkeypatch.setenv("PYAUTO_ROOT", str(root)) + assert registry.body_map_path() == root / layout / "repos.yaml" + + +def test_no_body_map_is_an_error_not_a_guess(tmp_path, monkeypatch): + monkeypatch.setattr(registry, "ORGAN_ROOT", tmp_path / "x" / "y" / "PyAutoPulse") + with pytest.raises(registry.RegistryError, match="cannot find PyAutoMind/repos.yaml"): + registry.body_map_path() + with pytest.raises(registry.RegistryError, match="no repos.yaml there"): + registry.body_map_path(tmp_path) + + +def test_get_names_the_known_instances(registry_file, fake_mind): + instances = registry.load(registry_file, mind=fake_mind) + assert registry.get(instances, "lens").repo == "autolens_profiling" + with pytest.raises(registry.RegistryError, match="known: lens"): + registry.get(instances, "nope") diff --git a/tests/test_summary.py b/tests/test_summary.py new file mode 100644 index 0000000..741e6f6 --- /dev/null +++ b/tests/test_summary.py @@ -0,0 +1,138 @@ +"""The profiling-summary v1 exchange contract and the comparison pairing.""" + +import copy +import math + +import pytest +from conftest import FIXTURES, fixture_doc + +from pulse import summary + +V1 = ("profiling-summary", 1) + + +def test_the_reader_imports_no_scientific_library(): + import subprocess + import sys + + code = ( + "import sys, json, pathlib; sys.path.insert(0, sys.argv[1]);" + "from pulse import cli, summary;" + "[summary.classify(json.loads(p.read_text())) for p in pathlib.Path(sys.argv[2]).glob('*.json')];" + "bad = [m for m in ('numpy', 'autolens', 'autoarray', 'autofit', 'autogalaxy', 'jax')" + " if m in sys.modules]; print(bad); sys.exit(1 if bad else 0)" + ) + root = str(FIXTURES.parents[1]) + proc = subprocess.run( + [sys.executable, "-c", code, root, str(FIXTURES)], capture_output=True, text=True + ) + assert proc.returncode == 0, proc.stdout + proc.stderr + + +def test_the_trimmed_live_feed_validates_clean(): + doc = fixture_doc("lens_summary_v1.json") + assert summary.classify(doc, V1) == ("ok", []) + assert len(doc["records"]) <= 20 and len(doc["comparisons"]) == 5 + assert all(not p.refused for p in summary.pair(doc)) + + +def test_valid_empty_feed_is_ok(): + assert summary.classify(fixture_doc("valid_empty.json"), V1) == ("ok", []) + + +def test_unsupported_version_is_refused_not_validated(): + outcome, errors = summary.classify(fixture_doc("unsupported_schema.json"), V1) + assert outcome == "unsupported" + assert "version 2" in errors[0] + + +def test_registered_schema_must_match(): + outcome, errors = summary.classify(fixture_doc("valid_empty.json"), ("inference-summary", 1)) + assert outcome == "unsupported" + + +def test_duplicate_record_id_is_invalid(): + outcome, errors = summary.classify(fixture_doc("duplicate_id.json"), V1) + assert outcome == "invalid" + assert any("duplicate record id" in e for e in errors) + + +def _mutate(fn): + doc = copy.deepcopy(fixture_doc("unknown_provenance.json")) + fn(doc) + return summary.validate(doc) + + +@pytest.mark.parametrize( + "mutation, needle", + [ + (lambda d: d.pop("records"), "missing required field 'records'"), + (lambda d: d.update(generated_at="2026-09-30 12:00"), "generated_at"), + (lambda d: d.update(evidence_updated_at=None), "without evidence_updated_at_reason"), + (lambda d: d.update(valid_until="2026-08-01T00:00:00Z"), "valid_until precedes"), + (lambda d: d.update(producer_revision="HEAD"), "producer_revision"), + (lambda d: d["records"][0]["measurement"].update(single_jit_s=math.nan), "non-finite"), + (lambda d: d["records"][0]["measurement"].update(single_jit_s=math.inf), "non-finite"), + (lambda d: d["records"][0].update(unit="MB"), "is not a runtime unit"), + (lambda d: d["records"][0].update(axis="speed"), "axis 'speed'"), + (lambda d: d["records"][0]["evidence"].update(path="../secret.json"), "evidence path"), + (lambda d: d["records"][0]["evidence"].update(path="/home/x/r.json"), "evidence path"), + (lambda d: d["records"][0]["evidence"].update(path="https://x/r.json"), "evidence path"), + (lambda d: d["records"][0]["provenance"].pop("qualified"), "provenance.qualified"), + (lambda d: d["comparisons"][0].update(status="regressed"), "status 'regressed'"), + (lambda d: d["comparisons"][0].update(policy="other"), "is not comparison_policy.id"), + (lambda d: d["coverage"]["observed"].update(points=-1), "non-negative"), + (lambda d: d.update(limitations=[""]), "limitations"), + ], +) +def test_contract_breaks_are_named(mutation, needle): + errors = _mutate(mutation) + assert any(needle in e for e in errors), errors + + +def test_a_memory_value_cannot_enter_a_seconds_series(): + errors = _mutate(lambda d: d["records"][0].update(unit="GiB")) + assert any("cannot enter a series of another unit" in e for e in errors) + + +def test_unknown_provenance_is_kept_and_counted_unqualified(): + doc = fixture_doc("unknown_provenance.json") + assert summary.classify(doc, V1)[0] == "ok" + assert len(doc["records"]) == 2 + assert summary.qualified_records(doc) == 1 + + +def test_compile_runtime_pair_is_refused_never_merged(): + (p,) = summary.pair(fixture_doc("axis_mismatch.json")) + assert p.group == "refused" + assert any("axis mismatch" in r for r in p.refused) + + +def test_changed_hardware_is_a_separate_group_and_a_mixed_pair_is_refused(): + pairs = summary.pair(fixture_doc("changed_hardware.json")) + groups = [p.group for p in pairs] + assert groups[0] == "cpu · cpu · float64" + assert groups[1] == "a100 · gpu · float32" + assert groups[2] == "refused" + assert "hardware identity changed" in pairs[2].refused[0] + + +def test_an_unrecorded_host_is_unknown_not_different(): + doc = copy.deepcopy(fixture_doc("changed_hardware.json")) + doc["records"][0]["provenance"]["host"] = None + assert not summary.pair(doc)[0].refused + + +def test_a_missing_endpoint_is_refused(): + doc = copy.deepcopy(fixture_doc("unknown_provenance.json")) + doc["comparisons"][0]["candidate"] = "9.9.9" + (p,) = summary.pair(doc) + assert p.group == "refused" and "not in records" in p.refused[0] + + +def test_second_producer_takes_the_same_code_path(): + doc = fixture_doc("second_producer.json") + assert doc["project"] != "autolens_profiling" + assert summary.classify(doc, V1) == ("ok", []) + (p,) = summary.pair(doc) + assert p.group == "a100 · gpu · mixed" and not p.refused