# Prove a Core with Hyperscale Assure

Assure is what your QA and audit teams use to prove a Core before it goes
live, and to keep that proof after. Hyperscale runs a Core's checks after
every save. Assure shows you the outcome, lets your team run its own suites
against a copy of the Product, signs what it found and hands it over as one
bundle.

Everything here runs in the sandbox. A suite never runs against live.

## What the checks found

A check is a `check` block in the program's HSX source
([HSX, checks](/docs/hsx.md)). A few seconds after each save, Hyperscale runs every
check in its own sandbox world, then one simulate pass with a fixed seed, and
stores the outcome beside the Core. `hsx check` on your laptop only counts
coverage, how many exposed actions a check runs. It never runs a check.

You can read the outcome in three places:

- **The Sandbox screen**, Checks tab: the status, when the checks ran, the
  Arc revision, the world start, the simulate seed, and every check with its
  verdict and failure.
- **The Tests document**, on the Core's Documents tab: the same results,
  each check as numbered steps with the outcome each step expected and the one
  it got, the coverage, and the conservation certificate's property results.
  It prints on A4.
- **`product.core.retrieve`**, as `validity.checks`, for your own tools,
  through the [HTTP API](/docs/api.md) or [MCP](/docs/mcp.md).

A failure names the step and what it found:

```text
step 3 lesson.pay: balances {"anna":"0","tom":"10000"}, expected {"anna":"0","tom":"15000"}
```

The same Core with the same outcome always gives the same Tests document,
byte for byte, with the same SHA-256. A second reading proves nothing changed.

## The certificate

`product.documents` returns an Assure certificate beside the five documents.
It names the Core digest, the Tests document's SHA-256, every check outcome,
the world and seed they ran with and the conservation verdict, and it is
signed.

```sh
hyperscale core certificate pbld_... > certificate.json
hyperscale core certificate pbld_... --verify
hyperscale core certificate --file certificate.json --verify --release https://arc.yourbank.example
```

`--verify` checks three things against the instance public key in your
installation's `/release.json`: the payload's digest, the instance key's
endorsement of the Assure key, and the signature. Change one byte of the
payload and it fails. Given a Core id rather than a file, it also checks the
certificate names that Core's digest. `--public-key <base64>` takes the key
directly when the machine cannot reach the installation.

A self-hosted Arc signs with an Assure key derived from its instance key, so
the instance key itself never reaches Arc. It signs once, when the checks
finish, and stores the certificate; every read returns that stored copy and
never signs again. Someone who rewrites the stored outcome in the database
gets no fresh signature: the certificate still says what the checks found,
and its Tests digest no longer matches the Tests document. A promoted or
restored Core with the same digest carries the certificate of the Core row
its checks ran on, and a Core checked before r442 has an unsigned one. The hosted service carries no
instance key, so its certificates arrive with `signature: null` and verify
nothing.

## Your own suites

Your QA team writes scenarios as JSON files in a folder beside the Core,
outside its source. A suite tries what the business will do, as the people
who will do it, and records what Arc allowed and what it refused.

```json
{
  "scenario": "A teller cannot release a loan",
  "customers": { "maya": { "name": "Maya Brooks", "fund": "1000" } },
  "staff": {
    "teller": { "role": "desk_teller" },
    "officer": { "role": "credit_officer" },
    "checker": { "role": "credit_checker" }
  },
  "steps": [
    {
      "create": "loan",
      "as": "loan",
      "by": "maya",
      "fields": { "amount": "500" }
    },
    {
      "run": "release",
      "on": "loan",
      "by": "teller",
      "refused": "status 403 \"missing_required_permission\""
    },
    { "run": "release", "on": "loan", "by": "officer", "approval": "release" },
    { "approve": "release", "by": "checker" }
  ]
}
```

| Field or step     | Does                                                                                    |
| ----------------- | --------------------------------------------------------------------------------------- |
| `customers`       | Sandbox test customers the run creates, each with a balance                             |
| `staff`           | The sandbox team members who act, each named by the staff role they hold                |
| `by`              | Who takes the step: a customer or a staff alias                                         |
| `refused`         | The step passes only if Arc refuses with that status and code, written as HSX writes it |
| `approval`        | The run waits for an approval; the step keeps it under this name                        |
| `approve`         | A staff member approves the waiting run by that name                                    |
| `fund`, `advance` | Add sandbox money, move the sandbox clock                                               |
| `expect`          | Checks `available`, `settled` or `pending` balances                                     |

Staff are real sandbox team members. Seat one per role in the console under
Team, give each the staff role the scenario names, and have each mint a
personal access token. The suite reads them from the environment, so no
credential sits in the files:

```sh
export HYPERSCALE_STAFF_TELLER="<personal access token>"
export HYPERSCALE_STAFF_OFFICER="<personal access token>"
export HYPERSCALE_STAFF_CHECKER="<personal access token>"
export HYPERSCALE_STAFF_CHECKER_PASSWORD="<password>"  # only for a member who approves
```

An approval re-enters the approver's password, as it does in the console. A
missing credential stops the run before its first call with
`staff_credentials_missing`. The CLI never adds a team member: a CLI login
cannot change the team.

Run a whole folder, each file on a fresh rehearsal copy of the Product:

```sh
hyperscale scenario run ./assure --rehearsal --json
```

Every step gets a verdict, `passed`, `failed` or `not_reached`, and a failed
step names its code. The command exits 1 if any scenario failed. Running the
suite again gives the same verdicts on the same Core digest. The report names
the Core the suite started on, and a suite whose Core changes partway stops
with `assure_core_changed`.

Hyperscale keeps each run report as a record on the Product, and the evidence
bundle carries it. The report says `stored: true` with its `recordId`. When
Arc refuses to keep it, the command warns, reports `stored: false` with the
reason and exits 1 with `assure_report_not_stored`, even if every scenario
passed.

A stored report is a record your team wrote, not a signed statement from
Hyperscale: anyone who can write records on the Product can store one. Treat
it as your team's own account of the run, and the certificate as
Hyperscale's.

An authorization matrix is one scenario that tries the same action as each
staff role, with `refused` on every role that should not get through. The
report then lists each role and what Arc did.

Suites run in the sandbox only. Against a live environment the CLI refuses
with `assure_live_refused` before it makes a call.

## One evidence bundle per Core

```sh
hyperscale core evidence pbld_... --out ./evidence
```

`product.evidence.export` returns everything an auditor needs about one Core
digest, each entry with its SHA-256, under one manifest digest:

| Entry                            | What it is                                               |
| -------------------------------- | -------------------------------------------------------- |
| `documents/<kind>.html`          | The five Core documents, Tests included                  |
| `checks.json`                    | `validity.checks`, the stored outcome                    |
| `certificate.json`               | The signed Assure certificate                            |
| `plan.json`                      | The promotion plan and its `planDigest`, if any          |
| `audit.json`                     | The audit events that name the Core, with their count    |
| `scenario-reports/<digest>.json` | Your suites' stored run reports for this digest          |
| `keys/instance-public-key.json`  | The instance public key the certificate verifies against |

The CLI checks every entry's SHA-256 before it writes the folder, and writes
`manifest.json` beside them. Two exports of the same digest with nothing new
since give the same manifest digest. A new suite run or a new audit event
about the Core adds an entry, so a later bundle differs from an earlier one
exactly by what happened in between.

The export needs `audit:read` as well as `product:read`, since it carries
audit events. A personal access token or an agent needs both
`products:read`, for the documents, and `activity:read`, the scope every
audit read takes. Each event keeps its chain digests and leaves its body out.
A bundle holds at most the 5,000 oldest events. `audit.json` carries
`total`, every event that names the Core, and `included`, the ones it holds,
and its media type in the manifest repeats both
(`application/vnd.hyperscale.audit-events+json; included=5000; total=7312`),
so a cut trail is never read as the whole one.
Suites run in the sandbox, so their reports ride in the sandbox Core's
bundle; a live Core's bundle carries the documents, certificate, checks, plan
and audit events.

The console's Documents tab downloads the certificate and the bundle too.

For agents: [OpenAPI document](https://hyperscale0.ai/openapi.json) · [MCP manifest](https://hyperscale0.ai/.well-known/mcp.json) · [HTTP API guide](https://hyperscale0.ai/docs/api.md) · [MCP guide](https://hyperscale0.ai/docs/mcp.md)
