Skip to content

Job notifications

VeriLib shows background job notifications for uploads, reclones, and atomizations on repositories you own or can edit. They appear in two places:

Surface URL / location Purpose
Header bell Every signed-in page (top navigation) Quick glance + dropdown list
Background jobs page /jobs (auth required) Full table view with In progress, Recent, and Hidden sections

The bell links to View all/jobs.

Not real-time push

Notifications are polled, not WebSockets. The UI refetches about every 5 seconds while jobs are active and about 30 seconds when idle. Refresh the page if you suspect a stale row.

What is a notification?

A notification is one row of work on one repository — not a separate database job entity. The frontend asks the API for repos in relevant states, then derives a human-readable status from existing data:

Source What it tells the UI
repos.status_id Whether the repo is still in-flight (initial, submitted, processing, …) or terminal (approved, rejected)
joblogsupload_response Clone/upload progress and errors from the upload processor
joblogslivelog Atomization progress streamed from the atomizer worker
RabbitMQ queue inspect (limited) Queue depth / position when a repo has no atoms yet and no livelog has started

Implementation: JobNotificationsService in verilib-frontend (public/app/Services/JobNotificationsService.php).

Scope — which repos appear

Notifications are built only for repositories where the signed-in user has edit access:

  • repos you own (repos.user_id), and
  • repos shared with you via reposhares with edit permission.

You will not see upload/atomize activity on repos you can only view.

What is excluded

These repos are not listed, even if status_id looks “active”:

  • initial repos with no job activity — no upload_response or livelog rows (idle placeholders, e.g. repo never started processing).
  • Terminal repos older than 30 days — completed/failed jobs drop off the Recent list after the lookback window.
  • Repos outside your edit scope.

Certification / validate-worker jobs are not part of this feature today — only the upload → atomize pipeline.

Notification kinds

Each item has a kind label in the UI:

Kind UI label Meaning
queue In queue Repo is waiting in the atomization RabbitMQ queue (no atoms yet, no livelog). Message may include queue position, e.g. #2 in line — 3 total queued.
upload Uploading Clone/upload phase — reading upload_response joblogs, or repo status is submitted.
atomize Atomizing Atomizer is running — latest message from livelog (e.g. Building libraries: …).
done Complete Terminal success — repo reached approved status. Message includes atom count when available.
error Failed Terminal failure — repo rejected, or last log entry carries an error message.

Active vs terminal phase

Phase When Bell behavior
active Repo still in-flight (initial, submitted, processing, …) Counts toward “in progress”; faster polling
terminal Repo approved or rejected Stays in Recent until you hide it or it ages out (30 days)

Clicking a notification opens the repo edit page: /edit?id={repo_id}.

How /jobs is organized

The /jobs page uses the same stats-table layout as certificates and lists three sections:

Section Contents
In progress Active-phase notifications
Recent Terminal notifications from the last 30 days
Hidden Items you dismissed with × (see below)

Columns: Repo, Summary, Status (kind tag), Message, Updated, Open, Hide / Restore.

Hide, dismiss, and restore

Dismissal is client-side only (browser localStorage). Nothing is deleted on the server.

Action Effect
× Hide (bell or table) Removes the item from the bell and from In progress / Recent. On /jobs it moves to Hidden.
Hidden → Restore Puts the item back in the bell and the appropriate section.
Open / click row Navigates to the repo. Does not hide the notification — use × for that.

Storage keys (per browser):

Key Purpose
verilib_notifications_dismissed Set of notification_id values the user hid
verilib_notifications_hidden_active For stuck active jobs: maps repo_idnotification_id so the same in-progress job stays hidden until a new job starts on that repo

A hidden in-progress job reappears automatically when atomization/upload restarts and the backend issues a new notification_id (derived from repo id, kind, and latest log id).

API

Method Path Auth Purpose
GET /v2/user/job-notifications Session (logged in) Returns { items: [...], active_count: N }

Each item shape (abbreviated):

{
  "notification_id": "5224:atomize:99",
  "repo_id": 5224,
  "slug": "secure-messaging",
  "summary": "Secure messaging protocols",
  "kind": "atomize",
  "phase": "active",
  "repo_status": "processing",
  "message": "Building libraries: SecureMessaging",
  "queue_info": null,
  "updated_at": "2026-08-11T12:59:05+00:00",
  "href": "/edit?id=5224"
}

notification_id is stable for a given repo + kind + latest log row. When processing advances and log ids change, ids update — which is why hide-on-active uses the repo-level snapshot above.

Web route (PHP, not /v2):

Route Auth View
GET /jobs Yes Mounts the React notifications bundle on #jobs-root

End-to-end flow

sequenceDiagram
  participant User
  participant Bell as Header bell /jobs
  participant API as GET /v2/user/job-notifications
  participant DB as MySQL repos joblogs
  participant MQ as RabbitMQ atomize queue

  User->>Bell: Open site (signed in)
  loop Every 5s active / 30s idle
    Bell->>API: Poll
    API->>DB: Repos user can edit in-flight or terminal
    API->>DB: upload_response + livelog per repo
    API->>MQ: Queue inspect (cap 5 repos, no atoms yet)
    API-->>Bell: items + active_count
  end
  User->>Bell: Hide ×
  Bell->>Bell: localStorage dismissed / hidden_active