Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
blank_issues_enabled: true
contact_links:
- name: Questions and answers (FAQ)
url: https://github.com/genclass-dev/GenClass-lib/blob/main/FAQ.md
about: Short answers to common questions (race conditions in React, stale responses, double submits, what it sends, what it costs), with links to the details.
- name: Ask a question in Discussions
url: https://github.com/genclass-dev/GenClass-lib/discussions/categories/q-a
about: Questions about installing, configuring or reading GenClass Runtime's reports.
- name: GenClass Discord
url: https://discord.gg/kN9kRnFtZm
about: Talk with the maintainers and other users.
- name: Report a security vulnerability
url: https://github.com/genclass-dev/GenClass-lib/blob/main/SECURITY.md
about: Please report security issues privately, not in a public issue; SECURITY.md says how.
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Default mode is `observe` (report only); `guard` is opt-in; `heal` is experiment
| `packages/nuxt/`, `packages/astro/` | `@genclass/nuxt` (a Nuxt module, `@nuxt/kit`, built with `@nuxt/module-builder`) and `@genclass/astro` (an Astro integration, `injectScript("page", ...)`): from options `{ mode, token?, telemetry?, devtools? }` they generate the runtime's own one line (`/auto` or `/auto/guard`) plus a `window.GENCLASS_CONFIG` module imported before it; browser only, nothing on the server; `@genclass/runtime` is a peer dependency. The generated code is pure (`src/source.ts`, `src/index.ts`) and the tests check it exactly, then build one fixture app. Workflow: `integrations.yml` (Node 24) |
| `docs/adoption/listings/` | how the framework packages and templates get listed (nuxt.com/modules entry and steps, astro.build/integrations, sveltesociety.dev, awesome-vue and Angular lists): research and draft entries; nothing is submitted from the repo |
| `bench/visual/` | the visual checks' bench (GitHub Actions only, `.github/workflows/visual-measure.yml`): false reports on the demos, templates, compat apps and about 40 public sites, recall on faults planted from the harness, cost; public sites are counted per check kind only, never named in the repo, its run logs or plain artifacts (per-site results only encrypted with the `VISUAL_BENCH_KEY` secret) |
| `bench/stall/` | `request-stalled` on the demos (`run.ts`, local, headless Chromium): false reports on clean and chaos trials, recall on planted 60 s hangs; numbers in RESULTS.md section 21 |
| `bench/stall/` | `request-stalled` on the demos (`run.ts`, local, headless Chromium): false reports on clean and chaos trials, recall on planted 60 s hangs; numbers in RESULTS.md section 23 |
| `compat/`, `templates/` | framework compatibility matrix (`RESULTS.md`) and starter templates (react-vite, nextjs, vue-vite, sveltekit, astro, nuxt, react-router, angular; `compat/templates-check.mjs` builds and boots them in Chromium against the packed runtime, module and integration); evaluation only |
| `telemetry-worker/` | the diagnostics collector with the dashboards and accounts (Cloudflare Worker). genclass.dev itself (the site, its admin and the pitch deck) and the page check (`scan-worker/`) live in the private repo genclass-dev/genclass-site, which has this repo as its `lib/` submodule |
| `research/` | earlier Jev research: extension, `jev_local` (Python encoder the training scripts import), benchmarks |
Expand Down
32 changes: 32 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cff-version: 1.2.0
message: "If you use GenClass Runtime in your work, please cite it with these metadata and name the version of @genclass/runtime you used."
type: software
title: "GenClass Runtime"
abstract: >-
GenClass Runtime (@genclass/runtime) is an open-source (Apache-2.0) browser library that reports race
conditions in web apps while they happen: stale responses that land over newer data, duplicate requests such as
double submits, inconsistent state and failure storms. A small model runs on the user's device, in a Web Worker on
WebGPU or WASM, and each report comes with its evidence. By default it only reports (observe): it never holds,
delays or changes a request, a response or a state write. The opt-in guard mode may act on a few of them, and
heal is experimental.
authors:
- name: "Daybot Solutions Inc."
website: "https://genclass.dev"
repository-code: "https://github.com/genclass-dev/GenClass-lib"
url: "https://genclass.dev"
license: Apache-2.0
# The newest published release of @genclass/runtime (npm `beta`; `latest` is 0.2.2, dated 2026-10-13 in the
# CHANGELOG and published to npm on 2026-10-15, before this one).
# Update both fields at each release.
version: "0.3.0-beta.0"
date-released: "2026-10-15"
keywords:
- race condition
- stale response
- double submit
- web app
- browser
- runtime monitoring
- on-device model
- WebGPU
- WebAssembly
116 changes: 86 additions & 30 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,68 @@
# Contributing
# Contributing to GenClass

Thanks for looking. This repository holds `@genclass/runtime` (the library), its model package, and everything
used to train and evaluate the model. Issues and pull requests are welcome; the rules below keep the measurements
honest.
How to change GenClass-lib, the repository of `@genclass/runtime` (GenClass Runtime, an open-source browser library
that reports race conditions in web apps), its model package, and everything used to train and evaluate the model:
where things are, what CI runs, the rules that keep the measurements honest, and how a release is made. To use
GenClass in an app, read the [package README](packages/runtime/README.md) instead.

Thanks for looking. Issues and pull requests are welcome.

## Where things are

- `packages/runtime/` is the library: `src/` (observers, causality, stores, facts, triage, the policy gate, actions,
the model host, devtools), `test/` (vitest), `bin/` (the `init` / `remove` / `fetch-model` CLI). Read
`docs/runtime/CONTRACT.md` (binding design rules), `docs/runtime/API.md` and `packages/runtime/INTERCEPTION.md`
before changing behaviour.
the model host, devtools, the measured visual checks in `src/visual/`, interaction analytics in `src/analytics/`),
`test/` (vitest; `test/browser/` holds the Playwright suites), `bin/` (the CLI: `init`, `remove`, `login`,
`connect`, `whoami`, `logout`, `fetch-model`, `info`). Read `docs/runtime/CONTRACT.md` (binding design rules),
`docs/runtime/API.md` and `packages/runtime/INTERCEPTION.md` before changing behaviour.
- `packages/runtime-model/` is the data-only model package and its model card.
- `packages/playwright/` is `@genclass/playwright` (0.1.0, not on npm yet), a Playwright reporter that turns the race
files the GenClass Playwright fixture writes into one markdown report for a pull request (the fixture is built
separately and has not shipped). `packages/genclass-runtime/` is `genclass-runtime`, the former short name for the
CLI: deprecated in this repository and not published by the release workflow, but not yet marked with
`npm deprecate` on the registry, so `npx genclass-runtime init` still installs its newest npm version, 0.1.0-beta.3,
with an unsupported runtime and no deprecation warning from npm. Marking it is a maintainer step:
`npm deprecate genclass-runtime "Use @genclass/runtime: npx @genclass/runtime init"`. Use
`npx @genclass/runtime@beta init` (or `npx @genclass/runtime init` for 0.2.x).
- `sim/`, `realapps/`, `training/` produce and train on the model's data; `demos/`, `compat/`, `bench/heal/`
evaluate the result. `docs/runtime/RESULTS.md` is where every measured number lives.
evaluate the result; `bench/visual/` measures the visual checks' false reports, recall and cost (GitHub Actions
only). `docs/runtime/RESULTS.md` is where every measured number lives.
- `telemetry-worker/` is the diagnostics collector with the dashboards and accounts on genclass.dev (a Cloudflare
Worker). `billing/plans.json` is the one place the plans are defined. The website itself is built in a separate,
private repository (see [Releasing](#releasing-maintainers)).
- `templates/` (starter apps with the runtime installed), `research/` (earlier research; the training scripts
import its `jev_local` encoder), `scripts/` (Azure VM helpers for training, and the Stripe setup script).
- `AGENTS.md` is the short guide for coding agents; it applies to people too.

## Build and test

Node ≥ 20. CI (`.github/workflows/ci.yml`) runs exactly this on every pull request:
Node ≥ 20. CI (`.github/workflows/ci.yml`, Node 22) runs three jobs on every pull request:

- **`runtime`**: typecheck, build and the unit tests of `@genclass/runtime`, exactly as below.
- **`visual-browser`**: the first-load size of `/auto` and the main entry against the merge base with `main` (fails
at 0.6 KB gzip growth), and the measured visual checks in Chromium with Playwright
(`test/browser/visual/playwright.config.ts`). Chromium is installed in CI only.
- **`telemetry-worker`**: the collector's unit tests (`cd telemetry-worker && npx vitest run`).

The `runtime` job:

```bash
ONNXRUNTIME_NODE_INSTALL=skip npm ci
ONNXRUNTIME_NODE_INSTALL=skip npm ci --no-audit --no-fund
npm run typecheck -w @genclass/runtime
npm run build -w @genclass/runtime
cd packages/runtime
NODE_OPTIONS=--expose-gc npx vitest run --exclude "test/browser/**" --exclude test/review-perf.test.ts
NODE_OPTIONS=--expose-gc npx vitest run test/review-perf.test.ts --retry=2 # timing budgets; reported, not blocking
```

One test: `npx vitest run test/delivery.test.ts -t "<name>"`. Playwright tests (`npm run test:browser`), the
tarball smoke test (`test/smoke/smoke.sh`), the sim, the real-app corpus, the demos' evaluation and training are
not run in CI; say in the PR which of them you could not run.
One test: `npx vitest run test/delivery.test.ts -t "<name>"`. `@genclass/playwright` has its own workflow,
`playwright-reporter.yml` (typecheck, build, vitest; it runs when `packages/playwright/` or the lockfile changes and
never blocks `ci.yml`). The visual bench (`visual-measure.yml`) runs on manual dispatch, and on pushes that change
the bench on the `wave2/visual` branch; it loads public sites, so it never runs on pull requests. `release.yml`
publishes from a tag (see [Releasing](#releasing-maintainers)).

Not run in CI: the model Playwright suite (`npm run test:browser`), the tarball smoke test (`test/smoke/smoke.sh`),
the install suite (`test/install/run-all.sh`), the sim and real-app generators, the demos' evaluation and training.
Say in the PR which of them you could not run.

## The rules

Expand All @@ -40,7 +72,12 @@ not run in CI; say in the PR which of them you could not run.
that adds a hold, a delay or an action on clean traffic needs a measurement, not an argument.
2. **No hardcoded bug patterns.** The runtime computes generic facts and decides what is salient; it never maps a
fact pattern to a diagnosis or an action with an if/then. Actions are chosen only by the policy gate from the
model's answers.
model's answers. The one exception is the measured visual checks in `src/visual/`: deterministic measurements
with documented thresholds, reported as kind `"check"` and never as a model finding. They never decide network
actions and never feed situations, facts, the event log, the gate or the model; their fixes are opt-in,
reversible and never run in `observe` (`docs/runtime/VISUAL.md`). One indirect path remains: a check step that
makes the browser lay out a very heavy page can take 50 ms or more, and the `perf` observer records that long task
as a `perf` event the model can read (VISUAL.md section 1).
3. **Model-visible text is frozen.** Anything the model reads (`packages/runtime/src/situation/*`, facts, question,
action and diagnosis wording, redaction output, op and event names) is tagged (`situation-v2.3`). Changing it
means a new tag, regenerated data, an updated `training/curriculum/rt.py` mirror and retraining. Open an issue
Expand All @@ -54,7 +91,11 @@ not run in CI; say in the PR which of them you could not run.
6. **`packages/runtime/test/review-*.test.ts` are a contract.** Fix `src/`, never the test.
7. **Dependencies.** `onnxruntime-web` is the only runtime dependency; ask before adding another. Keep the committed
root `package-lock.json` in sync.
8. **Releases** are published only by `.github/workflows/release.yml` from a `v*` tag, with npm provenance. Do not
8. **Telemetry stays disclosed** (the console notice, `packages/runtime/TELEMETRY.md`, both READMEs, the CHANGELOG),
sends no page text unless the app opts in, keeps every opt-out (`telemetry: false`, `?genclass=no-telemetry`,
the `localStorage` switch, Global Privacy Control) and never feeds a decision. Widening what is sent needs the
owner's OK.
9. **Releases** are published only by `.github/workflows/release.yml` from a `v*` tag, with npm provenance. Do not
publish from a laptop.

## Pull requests
Expand All @@ -68,21 +109,36 @@ not run in CI; say in the PR which of them you could not run.

## Releasing (maintainers)

In this order, so nothing on `main` points at a version npm does not have yet:

1. On the release branch (`release/<version>`): `packages/runtime/package.json` has the version, the CHANGELOG
section is final, CI is green, and the first-load limits in `test/bundle.test.ts` match the README and
`docs/runtime/RESULTS.md`.
2. Tag `v<version>` at that commit and push the tag; approve the `npm-publish` environment run of
`.github/workflows/release.yml`.
3. Check that the version is live: `npm view @genclass/runtime@<version> version` and
`curl -sI https://cdn.jsdelivr.net/npm/@genclass/runtime@<version>` (HTTP 200).
4. Only then merge the release branch into `main`. Both READMEs' quick starts pin the version in a CDN script tag;
merged before the publish finishes, the snippet on GitHub loads a 404.
5. Site: after the merge, regenerate `site/public` with `site/build.sh` (move `RT` in `site/build.py` to this version
when the site should show it; `build.sh` refuses a version the CDN does not serve), so `/docs/telemetry` and
`/privacy` match the released `TELEMETRY.md` and `PRIVACY.md`. Deploying the site is a separate, owner-approved
step.
`.github/workflows/release.yml` publishes `@genclass/runtime` to npm from a tag `v<version>` whose version equals
`packages/runtime/package.json`; its header comment is the authority on the order. In this order:

1. On the release branch (`release/<version>`): `packages/runtime/package.json` and `packages/runtime/src/version.ts`
(`RUNTIME_VERSION`) have the version (`release.yml` checks both), the CHANGELOG section is final and dated, CI is
green, and the first-load limits in `test/bundle.test.ts` match the README and `docs/runtime/RESULTS.md`. Every place
a reader sees the version says the same: the version notes at the top of `docs/runtime/API.md`,
`docs/runtime/OPTIONS-SPEC.md`, `packages/runtime/TELEMETRY.md` and `packages/runtime/INTERCEPTION.md` (and any other
page that opens with one), the CDN pins and the `@beta` commands in both READMEs, and the Versions lines in both
READMEs (`README.md` and `packages/runtime/README.md`).
2. The previous release is on npm as `latest` (`npm view @genclass/runtime dist-tags`) and
`https://cdn.jsdelivr.net/npm/@genclass/runtime@<that version>` answers 200.
3. Merge the release branch into `main` by pull request, with CI green: the READMEs link `TELEMETRY.md`,
`PRIVACY.md` and `RESULTS.md` at `blob/main`. When the READMEs pin the new version, their CDN snippet on GitHub
answers 404 until the publish finishes, so tag as soon as step 4 is done.
4. Deploy `telemetry-worker/` from that commit (`d1 migrations apply genclass-dashboard --remote`, then
`wrangler deploy`; `telemetry-worker/README.md`), together with the site's admin aggregates (in
genclass-dev/genclass-site: `site/src/admin.js` and `site/migrations-admin/`; ask its maintainer), before the
tag: a worker older than 0.3.0 counts possible detections as detections.
5. Tag `v<version>` on that `main` commit and push the tag; approve the `npm-publish` environment run of
`release.yml`.
6. Check the release: the dist-tags (a prerelease lands on the tag named after it and `latest` stays), the "Verify
the registry signature and provenance" step, `npm view @genclass/runtime@<version> version`, and that jsDelivr
serves `@<version>`, `/dist/cdn/worker.js` and `/dist/sinks/webhook.js` (HTTP 200). Then set `RUNTIME_ON_NPM` to
the version in `telemetry-worker/wrangler.toml` and in `telemetry-worker/wrangler.selfhost.toml` (the config
self-hosters deploy; its Connect panel names the runtime that sends tokens), and deploy the worker again.
7. Site: genclass.dev is built in the private repository genclass-dev/genclass-site, which has this repository as
its `lib/` submodule. After the merge, ask its maintainer to move that submodule, and the runtime version the
site's pages name, to this release, so `/docs/telemetry` and `/privacy` match the released `TELEMETRY.md` and
`PRIVACY.md`. Deploying the site is a separate, owner-approved step.

## Reporting a false flag

Expand Down
Loading
Loading