> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myrqen.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Scan lifecycle

> The eight phases of an assessment, the states a scan moves through, and the events a live report receives.

An assessment is a sequence of declared phases inside one session. The agent marks each
transition, so the terminal and any live report can follow along without inventing a
progress percentage.

```bash theme={null}
myrqen phase start discovery
myrqen phase complete discovery
```

## The eight phases

<Steps>
  <Step title="preflight">
    Identify the repository root and stack. Load the session context. Detect a local test
    or development runtime without mutating production configuration. Inventory local
    origins and the external origins the project references. Identify available test
    identities and safe fixtures. Note whether an isolated runtime is available, and say
    so calmly if it is not.
  </Step>

  <Step title="scope">
    Settle what is in bounds. Loopback is the normal target class. Every external origin
    stays out of bounds until it passes the [authorization
    gate](/concepts/authorization-and-safety).
  </Step>

  <Step title="discovery">
    Build a threat-oriented application map before hunting for bugs: entry points and
    routes, the authentication and session implementation, where authorization is
    enforced, data stores and trust boundaries, upload and download surfaces, outbound
    requests and webhooks, parsing and template and query construction, secret handling,
    admin endpoints, third-party integrations, and dependency manifests.
  </Step>

  <Step title="source_review">
    Start from the static pass's candidates rather than the file tree — each names a
    route, a line, and the data flow it believes in. Then look for plausible root causes
    the static pass could not reach: authorization missing at a server-side boundary,
    unsafe composition of queries or commands or templates or paths, insecure file
    handling, server-side fetches without destination validation, token and cookie and
    session mistakes, trust in client-controlled role or ownership identifiers, and
    security-relevant business-logic assumptions.
  </Step>

  <Step title="runtime_validation">
    Exercise routes against the local running service with representative safe inputs and
    the configured test identities, to establish whether a candidate is actually
    reachable and security-relevant. Anything risky goes through `action check` first.
  </Step>

  <Step title="access_control">
    Compare identities: unauthenticated, normal user A, normal user B for object-ownership
    boundaries, and a privileged user. The focus is server-side enforcement and object
    ownership, using non-destructive fixture objects. A class that cannot be tested
    because an identity or fixture is missing is recorded as a limitation, not guessed.
  </Step>

  <Step title="validation">
    Assign verification honestly, deduplicate, and — at `high` effort and above — run a
    false-positive challenge pass that argues the opposite of each candidate and keeps
    only what survives.
  </Step>

  <Step title="reporting">
    `session finish` validates every finding, renders all four formats, and syncs if this
    scan opted in.
  </Step>
</Steps>

## Session states

`ScanState` in `packages/contracts/src/domain.ts`:

`created` · `preflight` · `scope` · `discovery` · `assessment` · `validation` ·
`reporting` · `complete` · `cancelled` · `failed` · `policy_blocked`

Phase records themselves carry their own state: `pending`, `running`, `complete`, or
`skipped`, with start and completion instants and a duration.

## Cloud state

Separate from the scan state, because a scan is never blocked by the cloud.
`LocalCloudState`:

| State           | Meaning                                                                                       |
| --------------- | --------------------------------------------------------------------------------------------- |
| `not_requested` | Sync was declined, the device is unlinked, or the repository is unbound.                      |
| `quota_blocked` | The plan's cloud-report limit is reached. The scan still runs and still writes local reports. |
| `live`          | A cloud report shell exists and is receiving progress events.                                 |
| `finalizing`    | The report body is being uploaded and finalized.                                              |
| `synced`        | Finalized.                                                                                    |
| `sync_failed`   | The cloud leg failed. The scan continued locally.                                             |

## Live progress events

A synced report receives only allowlisted, privacy-safe events. The payload schema is
closed, so the scanner cannot deliver source, prose, evidence, or secrets through this
path even by accident — `schemas/scan-event.schema.json` is the contract, and the server
rejects anything that fails it with `UNSAFE_PAYLOAD_REJECTED`.

Event types (`ScanEventType`):

`report_created` · `phase_started` · `phase_completed` · `aggregate_updated` ·
`warning_safe` · `scan_completed` · `scan_failed`

An event may carry a phase, a stable `safeCode`, a short message, a duration, and an
aggregate of counts (`candidateCount`, `validatedCount`, and per-severity totals).
Nothing else.

Browsers read the stream over server-sent events at
`GET /api/v1/reports/{id}/events`, which re-checks report access before the stream opens,
replays the stored history, and heartbeats every 20 seconds. Streams have a bounded
lifetime (`SSE_MAX_STREAM_MS`, default 5 minutes) so no viewer can hold a container
through a deploy; the browser reconnects and the route replays.

## Ending a session

```bash theme={null}
myrqen --json session finish     # validate, render, sync if opted in
myrqen --json session cancel     # finish early, keep what was validated
```

Both write a complete local report. `cancel` is the honest way to stop: it keeps the
validated findings and the coverage notes rather than throwing the work away.
