@crvouga/atlas 1.20.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/dist/core/src/cli.d.ts +2 -2
- package/dist/core/src/cli.js +7 -1
- package/dist/critics/src/catalog-client.d.ts +91 -0
- package/dist/critics/src/catalog-client.js +194 -0
- package/dist/critics/src/cli-calibrate.d.ts +4 -0
- package/dist/critics/src/cli-calibrate.js +211 -0
- package/dist/critics/src/cli-common.d.ts +108 -0
- package/dist/critics/src/cli-common.js +155 -0
- package/dist/critics/src/cli-review.d.ts +4 -0
- package/dist/critics/src/cli-review.js +174 -0
- package/dist/critics/src/cli-watch.d.ts +4 -0
- package/dist/critics/src/cli-watch.js +191 -0
- package/dist/critics/src/cli.d.ts +13 -0
- package/dist/critics/src/cli.js +490 -0
- package/dist/critics/src/index.d.ts +3 -0
- package/dist/critics/src/index.js +3 -0
- package/dist/critics/src/judging.d.ts +8 -0
- package/dist/critics/src/llm.d.ts +120 -0
- package/dist/critics/src/llm.js +266 -0
- package/dist/critics/src/marks.d.ts +74 -0
- package/dist/critics/src/marks.js +76 -0
- package/dist/critics/src/registry.d.ts +125 -0
- package/dist/critics/src/registry.js +203 -0
- package/dist/critics/src/spool.d.ts +32 -0
- package/dist/critics/src/spool.js +129 -0
- package/dist/critics/src/uiclip.d.ts +82 -0
- package/dist/critics/src/uiclip.js +167 -0
- package/dist/reports/src/compose.d.ts +23 -1
- package/dist/reports/src/compose.js +29 -19
- package/dist/reports/src/critique-review.d.ts +111 -0
- package/dist/reports/src/critique-review.js +123 -0
- package/dist/reports/src/critique-row.d.ts +24 -0
- package/dist/reports/src/critique-row.js +39 -0
- package/dist/reports/src/evidence-types.d.ts +5 -0
- package/dist/reports/src/layer-merge.js +5 -0
- package/dist/reports/src/report-cli.d.ts +13 -0
- package/dist/reports/src/report-cli.js +6 -4
- package/dist/reports/src/report-index.d.ts +6 -0
- package/dist/reports/src/report-index.js +12 -0
- package/dist/reports/src/ui-catalog-cli.d.ts +10 -0
- package/dist/reports/src/ui-catalog-cli.js +391 -0
- package/dist/reports/src/ui-catalog-diff.d.ts +104 -0
- package/dist/reports/src/ui-catalog-diff.js +130 -0
- package/dist/reports/src/ui-catalog-entries.d.ts +147 -0
- package/dist/reports/src/ui-catalog-entries.js +190 -0
- package/dist/reports/src/ui-catalog-export.d.ts +82 -0
- package/dist/reports/src/ui-catalog-export.js +221 -0
- package/dist/reports/src/ui-catalog-publish.js +2 -2
- package/dist/reports/src/ui-catalog.d.ts +2 -0
- package/dist/reports/src/ui-catalog.js +1 -1
- package/dist/reports/src/ui-state.d.ts +2 -0
- package/dist/reports/src/ui-state.js +2 -2
- package/dist/schema/src/api.d.ts +653 -1
- package/dist/schema/src/api.js +44 -0
- package/dist/schema/src/cli-results.d.ts +991 -1
- package/dist/schema/src/cli-results.js +265 -1
- package/dist/schema/src/critique.d.ts +31 -0
- package/dist/schema/src/critique.js +26 -0
- package/dist/schema/src/server-config.d.ts +3 -3
- package/dist/server/src/app.js +28 -1
- package/dist/server/src/openapi.js +19 -2
- package/docs/agents.md +16 -2
- package/docs/critics.md +273 -9
- package/docs/extending.md +1 -1
- package/docs/reference/cli.md +126 -1
- package/docs/reference/core.md +1 -1
- package/docs/reference/critics.md +1131 -29
- package/docs/reference/http-api.md +40 -0
- package/docs/reference/reports.md +855 -0
- package/docs/reference/schema.md +197 -1
- package/docs/report-contract.md +2 -1
- package/docs/server.md +2 -0
- package/docs/ui-catalog.md +110 -13
- package/docs/ui.md +69 -2
- package/llms-full.txt +636 -26
- package/llms.txt +1 -1
- package/package.json +9 -1
- package/packages/critics/README.md +1 -0
- package/packages/schema/schemas/critic-calibrate-result.schema.json +274 -0
- package/packages/schema/schemas/critic-doctor-result.schema.json +74 -0
- package/packages/schema/schemas/critic-list-result.schema.json +90 -0
- package/packages/schema/schemas/critic-review-result.schema.json +397 -0
- package/packages/schema/schemas/critic-run-result.schema.json +249 -0
- package/packages/schema/schemas/critic-setup-result.schema.json +34 -0
- package/packages/schema/schemas/critic-watch-result.schema.json +211 -0
- package/packages/schema/schemas/critique-mark.schema.json +81 -0
- package/packages/schema/schemas/effective-delta.schema.json +337 -0
- package/packages/schema/schemas/effective-evidence.schema.json +337 -0
- package/packages/schema/schemas/layer-rows.schema.json +337 -0
- package/packages/schema/schemas/ui-catalog-diff-result.schema.json +201 -0
- package/packages/schema/schemas/ui-catalog-export-result.schema.json +83 -0
- package/packages/schema/schemas/ui-catalog-publish-result.schema.json +116 -0
- package/packages/schema/schemas/ui-catalog-status.schema.json +197 -0
- package/packages/server/openapi.json +6755 -4738
- package/packages/visualizer/src/app/AppShell.tsx +3 -1
- package/packages/visualizer/src/app/router.tsx +20 -7
- package/packages/visualizer/src/catalog/Picture.tsx +32 -0
- package/packages/visualizer/src/catalog/UiCatalogCompare.tsx +289 -0
- package/packages/visualizer/src/catalog/UiCatalogPage.tsx +18 -28
- package/packages/visualizer/src/catalog/history.ts +61 -0
- package/packages/visualizer/src/catalog/search.ts +14 -3
- package/packages/visualizer/src/components/Header.tsx +16 -4
- package/packages/visualizer/src/critiques/CritiquesPage.tsx +402 -0
- package/packages/visualizer/src/critiques/FindingOverlay.tsx +50 -0
- package/packages/visualizer/src/critiques/ranking.ts +54 -0
- package/packages/visualizer/src/critiques/search.ts +41 -0
- package/packages/visualizer/src/evidence/applicability-view.tsx +11 -7
- package/packages/visualizer/src/evidence/behaviors-page.tsx +22 -15
- package/packages/visualizer/src/evidence/evidence-context.tsx +2 -1
- package/packages/visualizer/src/explorer/Explorer.tsx +5 -0
- package/packages/visualizer/src/explorer/TestDetail.tsx +4 -1
- package/packages/visualizer/src/explorer/parts.tsx +19 -1
- package/packages/visualizer/src/explorer/playlist.tsx +11 -7
package/docs/critics.md
CHANGED
|
@@ -12,10 +12,20 @@ is not human review: it never changes whether a report passes.
|
|
|
12
12
|
- [What is available](#what-is-available)
|
|
13
13
|
- [The critic contract](#the-critic-contract)
|
|
14
14
|
- [A critique is a layer](#a-critique-is-a-layer)
|
|
15
|
+
- [Reading the catalog](#reading-the-catalog)
|
|
15
16
|
- [Running critics](#running-critics)
|
|
17
|
+
- [The `atlas critic` command](#the-atlas-critic-command)
|
|
18
|
+
- [Watching the catalog](#watching-the-catalog)
|
|
19
|
+
- [Reviewing and marking](#reviewing-and-marking)
|
|
20
|
+
- [Calibrating](#calibrating)
|
|
21
|
+
- [Configuring critics](#configuring-critics)
|
|
22
|
+
- [The built-in UIClip critic](#the-built-in-uiclip-critic)
|
|
23
|
+
- [The LLM critic and bringing your own AI](#the-llm-critic-and-bringing-your-own-ai)
|
|
24
|
+
- [When the server goes away](#when-the-server-goes-away)
|
|
16
25
|
- [State-aware judging, calibration and modes](#state-aware-judging-calibration-and-modes)
|
|
17
26
|
- [Authentication and authorization](#authentication-and-authorization)
|
|
18
27
|
- [Credentials](#credentials)
|
|
28
|
+
- [The viewer: needs polish](#the-viewer-needs-polish)
|
|
19
29
|
- [What is not here yet](#what-is-not-here-yet)
|
|
20
30
|
|
|
21
31
|
## What is available
|
|
@@ -25,11 +35,17 @@ Import `@crvouga/atlas/critics`. It needs no model, no provider SDK and no netwo
|
|
|
25
35
|
| You want | Use |
|
|
26
36
|
| --- | --- |
|
|
27
37
|
| Define a critic | `defineCritic` (the contract below) |
|
|
38
|
+
| List, page through, follow and fetch the pictures of the UI catalog | `createCatalogClient` ([below](#reading-the-catalog)) |
|
|
28
39
|
| Judge many images with caching, retries, rate limits, timeouts and budgets | `runCritic` |
|
|
29
40
|
| Store the opinions | `critiqueLayer`, `publishCritiques` (a layer of parts of kind `critique`) |
|
|
30
41
|
| Read them back | `readCritique`, `critiquesOfLayer`, `critiqueCurrency` |
|
|
31
42
|
| Read a score in context, measure a threshold, decide an exit code | `relativeVerdict`, `calibrate`, `gateDecision` |
|
|
32
43
|
| Keep keys out of configuration and logs | `parseCredentialRef`, `resolveCredential`, `assertNoLiteralCredentials`, `createRedactor` |
|
|
44
|
+
| Keep critiques that could not be sent and send them later | `spoolingStore`, `flushSpool` |
|
|
45
|
+
| A UIClip critic, an LLM critic over any provider | `@crvouga/atlas/critics/uiclip`, `@crvouga/atlas/critics/llm` |
|
|
46
|
+
| Run all of it from a terminal or CI | `atlas critic list \| setup \| doctor \| run \| watch \| review \| calibrate` ([below](#the-atlas-critic-command)) |
|
|
47
|
+
| Record that a person agrees or disagrees with an opinion | `markLayer`, `publishMarks`, `markStanding` ([below](#reviewing-and-marking)) |
|
|
48
|
+
| Rank states, compare critics | `rankCritiques`, `critiqueAgreement` (`@crvouga/atlas/reports/critique-review`) |
|
|
33
49
|
| Let a token publish critiques and nothing else | the `critic` role (below) |
|
|
34
50
|
|
|
35
51
|
The JSON Schema of the evidence is [`critique.schema.json`](../packages/schema/schemas/critique.schema.json). The
|
|
@@ -108,6 +124,226 @@ score does not fail it, and neither does a critic that crashed. A project that w
|
|
|
108
124
|
with `gateDecision` in `gate` mode, which is computed by the reader from critique data and never changes a check's
|
|
109
125
|
status, a slot or a winner.
|
|
110
126
|
|
|
127
|
+
## Reading the catalog
|
|
128
|
+
|
|
129
|
+
A critic reads the [UI catalog](ui-catalog.md) from the server; it never reads a store directly and needs no browser or
|
|
130
|
+
collection framework. `GET /api/reports/ui-catalog/entries` lists **entries**: one per captured state per profile that has a picture
|
|
131
|
+
stored in its layer, each with the hash of that picture (`image.sha256`), where its bytes are (`image.path`), its `state` kind
|
|
132
|
+
(`screen`, `overlay`, `loading`, `error`, `empty`, or `unknown` when the producer declared none: set `kind` in the state's
|
|
133
|
+
`atlas.ui-state` facts) and the `critiques` already made of it, each marked `current` or `earlier-image`.
|
|
134
|
+
|
|
135
|
+
| A critic wants to | It asks |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| Iterate everything, a page at a time | `?limit=` and the opaque `nextCursor` of the previous page as `?cursor=`. Entries are in key order and the cursor names the last key, so each entry is seen once and in the same order |
|
|
138
|
+
| Resume where it stopped | keep the `version` of the **first** page; later ask `?since=<version>` for the entries whose layer was added or changed since (an entry that is included but not new is harmless: the cache skips an image it has judged). A version the server does not remember is answered with the whole catalog and `since.honored: false` |
|
|
139
|
+
| Judge only what it has not judged | `?unjudgedBy=<critic>@<version>`: entries with no current critique with a verdict from that critic (a failed critique is retried) |
|
|
140
|
+
| Narrow | `?state=`, `?area=`, `?profile=`, `?route=`, `?q=` |
|
|
141
|
+
| Be told something changed | hold `/api/events`; a `report` event carries the new version, then read `?since=`. A missed event costs nothing: the next read covers it |
|
|
142
|
+
| Get a picture | `GET /api/reports` + `image.path`, the same safe attachment path every viewer uses; check the bytes against `image.sha256` |
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { createCatalogClient } from '@crvouga/atlas/critics';
|
|
146
|
+
|
|
147
|
+
const catalog = createCatalogClient({ url: 'https://atlas.example.com', token: process.env.ATLAS_CRITIC_TOKEN });
|
|
148
|
+
const { version, entries } = await catalog.read({ unjudgedBy: { name: 'uiclip', version: '1.0.0' } });
|
|
149
|
+
for (const entry of entries) judge(entry, await catalog.image(entry)); // image() refuses bytes that are not the hash
|
|
150
|
+
for await (const batch of catalog.follow({ since: version })) handle(batch.entries); // catch up on connecting and after every drop, none twice
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`follow` connects to the event stream, catches up with a `since` read, and then reads again after every `report` event. When the
|
|
154
|
+
connection drops it reconnects after a pause and the next read starts from the version it holds, so nothing is missed; an entry
|
|
155
|
+
is handed over once per picture. The token is sent as `Authorization: Bearer` and is never put in an address or an error. The
|
|
156
|
+
list is a function of the report, so the same layers in any order give the same entries.
|
|
157
|
+
|
|
158
|
+
## The `atlas critic` command
|
|
159
|
+
|
|
160
|
+
`atlas critic list | setup | doctor | run | watch | review | calibrate` runs critics on this machine (a laptop, CI, a worker). Every
|
|
161
|
+
command takes `--format json`; the documents validate against `critic-list-result`, `critic-setup-result`, `critic-doctor-result`,
|
|
162
|
+
`critic-run-result`, `critic-watch-result`, `critic-review-result` and `critic-calibrate-result`. The full usage is in the
|
|
163
|
+
[command reference](reference/cli.md).
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
atlas critic list # what is configured, ready, and where images go
|
|
167
|
+
atlas critic setup uiclip # fetch and verify the model checkpoint (the only download)
|
|
168
|
+
atlas critic doctor # server, token scope, catalog, model files, credentials, providers
|
|
169
|
+
atlas critic run --critic uiclip --unjudged # judge what uiclip has not judged yet
|
|
170
|
+
atlas critic run --critic vision --all --dry-run # how many, and where images would go; sends and publishes nothing
|
|
171
|
+
atlas critic watch --critic uiclip # a worker: judge new and changed entries as they arrive
|
|
172
|
+
atlas critic review # the ranked needs-polish list; accept or dismiss what critics found
|
|
173
|
+
atlas critic calibrate uiclip --good ok/ --bad broken/ --out calibration/uiclip.json
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- **Interactive when there is a terminal.** Missing choices (the critic, the server, the scope) are asked for, and a run that
|
|
177
|
+
sends images to a third party names the destination and the number of images and waits for a yes.
|
|
178
|
+
- **Never interactive without one** (no terminal, `--non-interactive`, or `--format json`): every choice is a flag, a missing one
|
|
179
|
+
exits `2` and names the flags, and sending images to a third party needs `--yes`. Nothing is ever prompted for.
|
|
180
|
+
- **Exit codes.** `0` it worked; `1` the answer is no (a critic failed on an entry, a gate was crossed, `doctor` found a
|
|
181
|
+
problem); `2` the command was wrong (a missing flag, a gate refused for lack of evidence, a configuration that holds a
|
|
182
|
+
credential). Stopping at a budget is not a failure.
|
|
183
|
+
- **`doctor`** reports each problem separately with how to fix it: the server unreachable; the token missing or not accepted; its
|
|
184
|
+
scope (a `read` token cannot publish, a `publish` or `admin` token can do more than a critic needs, and a server with no
|
|
185
|
+
tokens is open, so **every caller is an administrator**); a server too old to list the catalog; and, for each configured
|
|
186
|
+
critic, its model file and checksum, its optional dependencies, its credential, and whether its provider answers.
|
|
187
|
+
- **`setup uiclip`** downloads the checkpoint only if it is missing, verifies it against the pinned SHA-256 (a bad checksum is
|
|
188
|
+
an error, a bad download is discarded) and uses a verified file as it is. Judging never downloads anything and refuses a
|
|
189
|
+
checkpoint that does not match.
|
|
190
|
+
- **Scope.** `--all`, `--unjudged`, `--since <version>`, or filters (`--area`, `--profile`, `--state`, `--route`, `--q`); at least one
|
|
191
|
+
is required. A score is read against the project's scores of the same state kind and against the entry's previous picture
|
|
192
|
+
(`verdict.relative`).
|
|
193
|
+
- **Cost.** `--max-images`, `--max-tokens`, `--max-cost`, `--concurrency`, `--timeout-ms`; see [running critics](#running-critics).
|
|
194
|
+
- **Modes.** `--mode report|warn|gate`, `--threshold state=score`, `--calibration file.json`; see
|
|
195
|
+
[modes](#state-aware-judging-calibration-and-modes). `gate` is refused (exit `2`, before anything is spent) without a calibration of
|
|
196
|
+
this critic and version with held-out evidence for every state kind in scope.
|
|
197
|
+
|
|
198
|
+
## Watching the catalog
|
|
199
|
+
|
|
200
|
+
`atlas critic watch --critic <name>… --server <url>` is `run` as a worker. It follows the catalog (`createCatalogClient(…).follow`): it
|
|
201
|
+
catches up on connecting, then judges what arrives, and after every announcement and every reconnection it reads again from the version
|
|
202
|
+
it holds, so it misses no entry and judges none twice. A picture a critic has already judged is skipped by the cache without a call, so
|
|
203
|
+
starting a watch on a judged catalog costs nothing.
|
|
204
|
+
|
|
205
|
+
```sh
|
|
206
|
+
atlas critic watch --critic uiclip --critic vision --yes --max-cost 5 # until Ctrl-C, or the money is spent
|
|
207
|
+
atlas critic watch --critic uiclip --since <version> --state overlay,loading # resume from the version the last watch printed
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
- **Ends cleanly.** On Ctrl-C (or a termination signal), after `--max-batches n` batches, or when a budget is spent. What it finished
|
|
211
|
+
is published as it goes; at the end it prints what it did and the report version to resume from (`--since`). A budget
|
|
212
|
+
(`--max-images`, `--max-tokens`, `--max-cost`) is for the whole watch, not for each batch.
|
|
213
|
+
- **Same promises as `run`.** Images that leave the machine need `--yes` (or a yes at the terminal, asked once before it starts);
|
|
214
|
+
critiques the server cannot take are spooled and sent by the next invocation, in order, byte for byte; a score is read against its
|
|
215
|
+
state kind; a failed entry is recorded with its reason and exits `1` at the end. It reports and never gates: there is no `--mode`.
|
|
216
|
+
- `--dry-run` reads the catalog once and says what would be judged; nothing is sent or published. The one JSON document
|
|
217
|
+
(`critic-watch-result`) is printed when the watch ends.
|
|
218
|
+
- The server never runs a model and never holds a key: the critic runs where `watch` runs, such as a small worker beside CI.
|
|
219
|
+
|
|
220
|
+
## Reviewing and marking
|
|
221
|
+
|
|
222
|
+
`atlas critic review` is where people meet the opinions. It lists one critic's entries lowest first (by standing within the state kind
|
|
223
|
+
when every score has one, as the viewer does), with every finding and the marks already made.
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
atlas critic review --critic vision --limit 10 # the list; with a terminal it then asks about each entry
|
|
227
|
+
atlas critic review --entry 'home@ios' --accept --finding f1 --note 'Really cramped'
|
|
228
|
+
atlas critic review --entry 'home@ios' --dismiss # the whole opinion is wrong
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
- **A mark says whether the UI needs polish.** *Accept*: the opinion is right (the finding is valid). *Dismiss*: it is not. A mark is
|
|
232
|
+
about a whole opinion, or about one finding (`--finding <id>`, repeatable; a finding without an `id` can only be marked with the
|
|
233
|
+
whole opinion). With a terminal and no `--entry`, `review` walks the list and asks `[a]ccept, [d]ismiss, [s]kip, [q]uit` for each
|
|
234
|
+
finding; without one, every choice is a flag.
|
|
235
|
+
- **A mark is a layer.** It is a check in a part of kind `critique` with the decision in `extensions["atlas.critique-mark"]`
|
|
236
|
+
([schema](../packages/schema/schemas/critique-mark.schema.json)), published under the producer `critic.review.<reviewer>`
|
|
237
|
+
(`--reviewer`, `ATLAS_REVIEWER`, else `reviewer`; a name the reviewer chooses, never an account). That is within what a `critic`-role
|
|
238
|
+
token may publish, so marking needs no more power than critiquing (a `publish` or `admin` token may too, a `read` token may not, and
|
|
239
|
+
the server answers `403` and stores nothing). The server may refuse a mark; it never alters one.
|
|
240
|
+
- **Evidence, never a result.** A mark is in a part of kind `critique`, so it is never counted, never in `atlas report status`, and
|
|
241
|
+
never changes a status, a slot or a winner. A reviewer holds one mark per critic and finding of an entry: a newer mark of theirs
|
|
242
|
+
replaces the older, and reviewers who disagree are shown as disagreeing (`disputed`). A mark names the picture it was made about; when
|
|
243
|
+
the picture changes, the mark is shown as about an earlier picture and counts for nothing now, like the critique it was about.
|
|
244
|
+
- **Read back** on each entry of `GET /api/reports/ui-catalog/entries` as `marks`, in `atlas critic review --format json`
|
|
245
|
+
(`critic-review-result`), by `markStanding`, and in the viewer. A server that predates marks sends none, which means none.
|
|
246
|
+
- **It feeds calibration.** See [calibrating](#calibrating).
|
|
247
|
+
|
|
248
|
+
## Calibrating
|
|
249
|
+
|
|
250
|
+
`atlas critic calibrate <name>` measures a critic against labelled examples, per state kind (`calibrate` as a command), so a threshold is
|
|
251
|
+
chosen from evidence and `gate` mode can be allowed.
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
# Pictures in directories. A subdirectory's name is the state kind of the pictures in it; pictures directly in a directory get --state.
|
|
255
|
+
atlas critic calibrate uiclip --good examples/ok --bad examples/broken --heldout-good holdout/ok --heldout-bad holdout/broken --out calibration/uiclip.json
|
|
256
|
+
# Or what reviewers decided: an accepted whole opinion is a bad example, a dismissed one a good example.
|
|
257
|
+
atlas critic calibrate uiclip --from-marks --server https://atlas.example.com --out calibration/uiclip.json
|
|
258
|
+
atlas critic run --critic uiclip --all --mode gate --calibration calibration/uiclip.json
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
- The critic judges the pictures here, with the same consent (`--yes` for a critic that sends images away), timeouts and budgets as `run`;
|
|
262
|
+
`--dry-run` counts them and says where they would go. Nothing is published: the calibration is a document, with the critic's name,
|
|
263
|
+
version, model and parameters, that you commit beside the configuration.
|
|
264
|
+
- It records, per state kind, the sample sizes, how many are bad and good, the threshold chosen, precision and recall, and **whether the
|
|
265
|
+
figures are in-sample**. A threshold is chosen only on examples that are not held out; `--heldout-*` pictures measure it. Marks are
|
|
266
|
+
never held out, so figures from marks alone are in-sample.
|
|
267
|
+
- Examples left out are named with the reason: the critic could not score the picture, reviewers disagree, the marks were about an
|
|
268
|
+
earlier picture, or the critic judged it as another version. Finding-level marks are not examples.
|
|
269
|
+
- The result says whether `gate` would accept it (`gate.eligible`) and, if not, what is missing per state kind (at least 10 bad and 10
|
|
270
|
+
good examples, measured on held-out examples).
|
|
271
|
+
|
|
272
|
+
## Configuring critics
|
|
273
|
+
|
|
274
|
+
`atlas critic` reads `atlas.critics.json` (or `--config`). It may be committed: it names a credential by **reference**
|
|
275
|
+
(`env:NAME`, `file:PATH`) and a literal credential in it is refused, with a message that says where and never repeats it.
|
|
276
|
+
Paths are relative to the file.
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"server": { "url": "https://atlas.example.com", "token": "env:ATLAS_CRITIC_TOKEN" },
|
|
281
|
+
"critics": {
|
|
282
|
+
"uiclip": { "type": "uiclip", "checkpoint": { "path": ".atlas/models/uiclip.onnx", "sha256": "<64 hex digits you pinned>", "url": "https://models.example.com/uiclip.onnx" } },
|
|
283
|
+
"vision": { "type": "llm", "baseUrl": "https://llm.example.com/v1", "apiKey": "env:LLM_API_KEY", "model": "<model id>", "rubricFile": "rubric.md" },
|
|
284
|
+
"claude": { "type": "llm", "provider": "anthropic", "apiKey": "env:ANTHROPIC_API_KEY", "model": "<model id>" },
|
|
285
|
+
"gemini": { "type": "llm", "provider": "gemini", "apiKey": "env:GEMINI_API_KEY", "model": "<model id>" },
|
|
286
|
+
"contrast": { "type": "module", "module": "./critics/contrast.ts" }
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The server is `--server`, `server.url`, `ATLAS_SERVER_URL` or an https `ATLAS_STORE`; the token is `server.token`,
|
|
292
|
+
`ATLAS_CRITIC_TOKEN` or `ATLAS_TOKEN`, and is refused over plain `http://` beyond this machine. A `module` critic is any
|
|
293
|
+
file whose default export is a `defineCritic` result (a heuristic, a classic model, a wrapper around your own service), on
|
|
294
|
+
equal footing with the others; its `name` must equal its key, because the name is the producer of its layers. Critiques are
|
|
295
|
+
published as `critic.<name>`.
|
|
296
|
+
|
|
297
|
+
## The built-in UIClip critic
|
|
298
|
+
|
|
299
|
+
`@crvouga/atlas/critics/uiclip` is a model-based critic that gives one score per image and keeps images on this machine. It is an
|
|
300
|
+
**adapter**: importing it needs nothing installed, and the model runs in an ONNX Runtime session opened only when a run starts
|
|
301
|
+
(`loadOnnxRuntime`, which needs the optional `onnxruntime-node` and `sharp` and names whichever is missing). A test or another
|
|
302
|
+
runtime passes its own `UiclipRuntime` (`score(image)`), so no model is needed to test anything.
|
|
303
|
+
|
|
304
|
+
- **Pinned checkpoint.** You pin the SHA-256 of the checkpoint in the configuration. Atlas ships no checkpoint address: the
|
|
305
|
+
weights' license must be checked before a project downloads them, and that choice is yours.
|
|
306
|
+
- **`setupUiclip`** is the only place anything is downloaded (https only, hashed as it arrives, discarded on a mismatch);
|
|
307
|
+
`verifyCheckpoint` refuses a missing, unpinned or different file; inference never downloads.
|
|
308
|
+
- **Report-only by design.** A single global score cannot say what to fix, and ordinary loading overlays and bottom sheets score
|
|
309
|
+
poorly. A run reports the score with its standing among the scores of the same state kind, so a loading overlay is compared with
|
|
310
|
+
other loading overlays; calibrate before reading it as a threshold.
|
|
311
|
+
- **Not validated against a particular checkpoint.** The preprocessing is CLIP's (resize to 224 by 224, normalise) and the score is
|
|
312
|
+
the first output; measure the critic on your own labelled examples with `calibrate` before trusting it.
|
|
313
|
+
|
|
314
|
+
## The LLM critic and bringing your own AI
|
|
315
|
+
|
|
316
|
+
`@crvouga/atlas/critics/llm` asks a vision-capable model to review an image against a **rubric** and answer with structured
|
|
317
|
+
findings. It is provider-agnostic: an `LlmProvider` is `complete(request)` plus declared capabilities, so a developer brings their own
|
|
318
|
+
model and account. Three adapters ship, all over plain `fetch` so there is no SDK to install: `openAiCompatibleProvider` speaks the
|
|
319
|
+
widely implemented chat-completions protocol (hosted services and local servers alike), `anthropicProvider` the Messages API and
|
|
320
|
+
`geminiProvider` the Gemini API. In the configuration `provider` is `openai-compatible` (the default, needs `baseUrl`), `anthropic` or
|
|
321
|
+
`gemini` (their own hosts by default; `apiKey` is required). A provider for anything else is a few lines.
|
|
322
|
+
|
|
323
|
+
- The rubric is recorded as a hash. The answer must be one JSON object with a `score` and optional `findings`; anything else is
|
|
324
|
+
`invalid-output` and no score is invented. A provider's `429` (and Anthropic's `529`, overloaded) becomes a rate limit with its `Retry-After`; a timeout, a refused
|
|
325
|
+
credential and an unreachable provider are failed critiques with a reason code.
|
|
326
|
+
- The key is read from its reference when the critic is built, sent only in a request header (`Authorization`, `x-api-key` or `x-goog-api-key`, never in an address), and kept out of every result,
|
|
327
|
+
progress line, error and JSON document (the runner redacts what it records). Plain `http` is allowed only for a provider on this
|
|
328
|
+
machine.
|
|
329
|
+
- **Images may leave the machine.** `describe().sendsImagesTo` is the provider's host, shown by `list`, `doctor` and `run --dry-run`
|
|
330
|
+
and confirmed before a run that sends images there.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
import { createLlmCritic, openAiCompatibleProvider } from '@crvouga/atlas/critics/llm';
|
|
334
|
+
|
|
335
|
+
const critic = createLlmCritic({ model: 'my-vision-model', rubric: 'Judge spacing and contrast.', provider: openAiCompatibleProvider({ baseUrl: 'https://llm.example.com/v1', apiKey }) });
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## When the server goes away
|
|
339
|
+
|
|
340
|
+
A run that cannot reach the server while publishing does not lose its work. The objects of the layer (its files, the layer, its
|
|
341
|
+
catalog entry) are written to the spool directory (`.atlas/critic-spool`, or `--spool`, or `spool` in the configuration); the run
|
|
342
|
+
reports how many, and exits normally. The next `atlas critic run` sends them first, **byte for byte what was written and in the
|
|
343
|
+
order it was written**, and removes each once the server has it. A layer is content-addressed and the store protocol is
|
|
344
|
+
idempotent, so one that did arrive is not duplicated, and a spool that is empty is not an error. A refusal (`401`, `403`, `409`,
|
|
345
|
+
`413`, `422`) is not spooled: it will not pass by waiting. `spoolingStore` and `flushSpool` do the same for your own code.
|
|
346
|
+
|
|
111
347
|
## Running critics
|
|
112
348
|
|
|
113
349
|
`runCritic` owns everything around the judgement; a critic only judges one image.
|
|
@@ -176,15 +412,43 @@ run time (`resolveCredential`) and every message the runner records goes through
|
|
|
176
412
|
`createRedactor`) that removes them, in their URL-encoded and base64 forms too, and anything shaped like a provider key,
|
|
177
413
|
token or JWT. A credential never reaches a layer, a progress event or an error message.
|
|
178
414
|
|
|
415
|
+
## The viewer: needs polish
|
|
416
|
+
|
|
417
|
+
`Needs polish` (`/critiques`, in the spec-type menu once any critic has recorded an opinion) ranks the captured states one critic
|
|
418
|
+
judged, lowest first, so the likeliest problems are reviewed first. When every ranked score carries its standing within its state
|
|
419
|
+
kind, that standing ranks them (a loading overlay is not compared with a full screen); otherwise the raw score does, read as
|
|
420
|
+
higher-is-better. The address holds the critic, the state kind and the open entry.
|
|
421
|
+
|
|
422
|
+
- **Opinions, not results.** Critiques have their own place, wording and mark, never a passed or failed mark, and are never in a test
|
|
423
|
+
count or the gate.
|
|
424
|
+
- **Anchored to pixels.** A state whose picture changed since it was judged is listed apart as *not judged at the current picture*, its
|
|
425
|
+
older opinion shown as judging an earlier picture; it is never ranked and never hidden.
|
|
426
|
+
- **Failures are data.** A critic that could not judge says why (the reason code) and that this says nothing about the picture.
|
|
427
|
+
- **Detail.** An open entry shows the verdict and its standing, every finding (category, severity, where, why, suggestion; unknown
|
|
428
|
+
categories and severities are shown as they are) and where the opinion came from: critic, version, model, parameters, the hash of
|
|
429
|
+
the picture it judged, the layer and the cost.
|
|
430
|
+
- **Findings on the picture.** An open entry draws each finding that has a region as a numbered box on the picture, in its severity's
|
|
431
|
+
color and never by color alone: the number matches the findings table, where *Locate* highlights one. Regions in `normalized`
|
|
432
|
+
(0..1) or `px` (pixels of the stored picture, using the picture's size) units are drawn; a region in another unit, or none, is
|
|
433
|
+
listed and not drawn. A critique that judged an earlier picture is not drawn on the new one.
|
|
434
|
+
- **Agreement across critics.** The *Agreement across critics* tab compares each critic's opinion of the picture an entry has now. A
|
|
435
|
+
critic *flags* a UI when its label says `needs-polish`, when it has findings, or, with neither, when its score is in the lowest quarter
|
|
436
|
+
of its state kind; a bare score with no standing, or a critic that failed, gives *no view* and never makes critics agree. Entries that
|
|
437
|
+
every critic flags come first, then those they disagree about; an entry only one critic judged is counted, not compared. It is a
|
|
438
|
+
reading for people, not a verdict, a status or a gate.
|
|
439
|
+
- **Marks.** The list and the open entry show what reviewers decided (accepted, dismissed, disputed, not reviewed), per finding and for
|
|
440
|
+
the whole opinion, with their notes. The viewer only reads: a browser's sign-in box may look but not write, so it names the
|
|
441
|
+
`atlas critic review` command that marks.
|
|
442
|
+
|
|
179
443
|
## What is not here yet
|
|
180
444
|
|
|
181
|
-
|
|
182
|
-
|
|
445
|
+
Out of scope until the open questions of [issue 50](https://github.com/crvouga/atlas/issues/50) are settled, because they need the
|
|
446
|
+
weights, a license or a network that this repository does not have:
|
|
183
447
|
|
|
184
|
-
- the **
|
|
185
|
-
the
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
-
|
|
190
|
-
|
|
448
|
+
- the **UIClip critic's parity** with the in-house package it is meant to absorb: its exact preprocessing and score head, checked
|
|
449
|
+
against a real checkpoint. No checkpoint address ships until the weights' license is settled, so the pin is yours; measure it
|
|
450
|
+
on your own examples with `atlas critic calibrate` before trusting a score;
|
|
451
|
+
- adapters for providers beyond OpenAI-compatible, Anthropic and Gemini, and access by a local command-line agent or a provider's
|
|
452
|
+
OAuth sign-in (whether a consumer subscription may be used that way is per provider's terms);
|
|
453
|
+
- heuristic and classic ML critics shipped in the package, a flow-level or before-and-after critic, and server-hosted execution (never
|
|
454
|
+
planned: the server does not run models).
|
package/docs/extending.md
CHANGED
|
@@ -249,7 +249,7 @@ Annotation `type`: `note`, `warning`, `deprecation`, `issue`, `accessibility`, `
|
|
|
249
249
|
| A kind of file Atlas has never seen | Attach it with its media type and a `role`. It is stored and offered for download today. |
|
|
250
250
|
| Structured data of your own | Put it in `extensions` under a name you own. It is kept, and shown as raw data. |
|
|
251
251
|
| A new annotation type, role or step kind | Use it. Open vocabularies need no registration. |
|
|
252
|
-
| An automated reviewer's opinion of a captured UI | A [critique](critics.md): a part of kind `critique` with the `atlas.critique` extension. It is never counted and never gates. |
|
|
252
|
+
| An automated reviewer's opinion of a captured UI | A [critique](critics.md): a part of kind `critique` with the `atlas.critique` extension. It is never counted and never gates. A person's accept or dismiss of it is the same kind of part with the `atlas.critique-mark` extension. |
|
|
253
253
|
| Something that should be shown well | Ask for a renderer (below). |
|
|
254
254
|
| A field every tool should have | Open an issue. It is added as an optional field, and the rules above guarantee nothing breaks. |
|
|
255
255
|
|
package/docs/reference/cli.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated from the usage text each command prints (`atlas <command> --help`) by `bun run docs`. Do not edit.
|
|
4
4
|
|
|
5
|
-
Add `--format json` (alias `--json`) to `init`, `report publish`, `stream`, `merge`, `doctor` and `
|
|
5
|
+
Add `--format json` (alias `--json`) to `init`, `report publish`, `stream`, `merge`, `doctor`, `status`, every `ui-catalog` command and `critic list`, `setup`, `doctor`, `run`, `watch`, `review` and `calibrate` for a JSON document on standard output (schemas in `@crvouga/atlas/schemas`). Exit codes: `0` it worked, `1` it ran and the answer is no, `2` the command was wrong.
|
|
6
6
|
|
|
7
7
|
## atlas
|
|
8
8
|
|
|
@@ -21,6 +21,8 @@ atlas — executable statecharts
|
|
|
21
21
|
atlas dev [--port 5180] develop the Atlas server and client on one host
|
|
22
22
|
atlas init [--server <url>] [--write] integrate this project: detect its suites, print the plan (atlas init --help)
|
|
23
23
|
atlas report publish|stream|status|merge|doctor|policy … layered evidence for any kind of spec (atlas report --help)
|
|
24
|
+
atlas critic list|setup|doctor|run … automated reviewers that mark which UIs need polish (atlas critic --help)
|
|
25
|
+
atlas ui-catalog plan|publish|status|diff|export … the UI catalog of captured states (atlas ui-catalog --help)
|
|
24
26
|
|
|
25
27
|
--workers path attempts that run at once (default: one per CPU, capped by the driver)
|
|
26
28
|
--seed only paths that start from this seed ("start" for paths setup starts); repeatable
|
|
@@ -172,3 +174,126 @@ atlas report — layered evidence for any kind of spec
|
|
|
172
174
|
|
|
173
175
|
Exit codes: 0 ok, 1 the report does not pass (or a check failed), 2 the command was wrong.
|
|
174
176
|
```
|
|
177
|
+
|
|
178
|
+
## atlas ui-catalog
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
atlas ui-catalog — a browsable inventory of captured UI states, from any collector
|
|
182
|
+
|
|
183
|
+
atlas ui-catalog plan --states <file.json> --producer <name> [--store <dir|s3://bucket/prefix|https://…>]
|
|
184
|
+
[--environment <name>] [--param key=value]... [--shard <label>]
|
|
185
|
+
[--branch <b>] [--sha <s>] [--run-url <u>] [--run-id <id>] [--run-title <t>] [--recorded-at <iso|ms>]
|
|
186
|
+
atlas ui-catalog publish --captures <file.json> --producer <name> [the same flags as plan]
|
|
187
|
+
[--attach-root <dir>]... [--max-picture-mb <n>]
|
|
188
|
+
atlas ui-catalog status [--store <dir|s3://…|id=url>]... [--backends <module>] [filters] [--branch <name>]...
|
|
189
|
+
[--ignore-modified] [--format text|json|markdown]
|
|
190
|
+
atlas ui-catalog diff --from <commit> --to <commit> [--store …]... [--backends <module>] [filters]
|
|
191
|
+
[--fail-on-change] [--format text|json|markdown]
|
|
192
|
+
atlas ui-catalog export --out <file.html> [--store …]... [--backends <module>] [filters]
|
|
193
|
+
[--images inline|none] [--max-mb <n>] [--manifest <file.json>] [--title <t>]
|
|
194
|
+
|
|
195
|
+
filters (status, diff, export): --q <words> --coverage a,b --profile <key|label>... --area a --route r --cohort c
|
|
196
|
+
--flag f --surface s --producer p
|
|
197
|
+
|
|
198
|
+
plan Write one layer of kind ui-plan: the states (and with "inventory": true, the surfaces) that should exist under
|
|
199
|
+
this profile. Every entry is not-run, so a plan never counts as a pass. The file is {"states":[{"id":…,
|
|
200
|
+
"title"?,"route"?,"fixture"?,"cohort"?,"area"?,"kind"?,"flags"?,"covers"?,"inventory"?}]} or just that list.
|
|
201
|
+
publish Write one layer of kind ui-state: the states one collector or shard captured under this profile. The file is
|
|
202
|
+
{"states":[{"id":…,"title"?,"status"?:"passed|failed|running|not-run","detail"?,"route"?,"fixture"?,"cohort"?,
|
|
203
|
+
"area"?,"kind"?,"flags"?,"covers"?,"labels"?,"tags"?,"durationMs"?,"screenshot"?:"file.png"|{"path"|"uri",
|
|
204
|
+
"width"?,"height"?,"contentType"?}}]}. A picture file is read from beside the file and each --attach-root, never
|
|
205
|
+
from a hidden file or a link out. A passed state whose picture cannot be read is published as failed, with the
|
|
206
|
+
reason: a state without its picture is not shown as captured.
|
|
207
|
+
--environment and each --param key=value are the profile (a viewport, a color scheme, a device): another
|
|
208
|
+
profile is another result side by side. --shard only describes the layer; it never splits a result.
|
|
209
|
+
--recorded-at defaults to the modification time of the file, so publishing the same file twice is one layer.
|
|
210
|
+
status Read every store and print the catalog's summary. Exit 1 unless the catalog holds a state and there is nothing
|
|
211
|
+
to attend to: a failed capture, a state a plan expects with nothing captured, a capture still in progress, a
|
|
212
|
+
backend or layer that could not be read. Without a plan nothing is expected, so nothing is missing.
|
|
213
|
+
--profile takes a profile's key or its label, as printed by status.
|
|
214
|
+
diff Set the catalog recorded at one commit (--from) against another (--to): each state in each profile is paired
|
|
215
|
+
with itself and is unchanged, changed in coverage, changed in picture (the stored bytes differ), unverified (a
|
|
216
|
+
side has no content hash), only in --to (added) or only in --from (removed). A commit is the whole id or at
|
|
217
|
+
least 7 digits of it. Exit 0 unless a store could not be read, or, with --fail-on-change, anything differs.
|
|
218
|
+
export Write the catalog as one HTML file with its pictures embedded and its manifest in it: no server, no network.
|
|
219
|
+
It is the catalog at the moment it was made. --images none leaves the pictures out. --max-mb (default 32) limits
|
|
220
|
+
the embedded pictures; those past it are listed in the page as left out, and the manifest stays complete.
|
|
221
|
+
--manifest writes the catalog's JSON manifest too.
|
|
222
|
+
|
|
223
|
+
--format json (alias --json) every subcommand prints one JSON document instead of prose
|
|
224
|
+
(schemas: ui-catalog-publish-result, ui-catalog-status, ui-catalog-diff-result, ui-catalog-export-result).
|
|
225
|
+
A command that is wrong is {"ok":false,"error":{"message":…,"code":"usage"}} on standard error.
|
|
226
|
+
A store is a directory, s3://bucket/prefix or an Atlas server (https://…), exactly as for atlas report; select a project
|
|
227
|
+
with --project <slug> or ATLAS_PROJECT. When no --store is given, ATLAS_STORE is used.
|
|
228
|
+
|
|
229
|
+
Exit codes: 0 ok, 1 the answer is no (see each command), 2 the command was wrong.
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## atlas critic
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
atlas critic — automated reviewers of the UI catalog
|
|
236
|
+
|
|
237
|
+
atlas critic list [--config atlas.critics.json] [--format text|json]
|
|
238
|
+
atlas critic setup <name> [--config atlas.critics.json] [--format text|json]
|
|
239
|
+
atlas critic doctor [--server <url>] [--critic <name>]... [--config atlas.critics.json] [--format text|json]
|
|
240
|
+
atlas critic run --critic <name>... ( --all | --unjudged | --since <version> | filters ) [--server <url>]
|
|
241
|
+
[--area a,b] [--profile key] [--state screen,overlay] [--route r] [--q words]
|
|
242
|
+
[--dry-run] [--yes] [--non-interactive] [--force]
|
|
243
|
+
[--max-images n] [--max-tokens n] [--max-cost usd] [--concurrency n] [--timeout-ms n]
|
|
244
|
+
[--mode report|warn|gate] [--threshold state=score]... [--calibration file.json]
|
|
245
|
+
[--spool dir] [--project slug] [--config atlas.critics.json] [--format text|json]
|
|
246
|
+
atlas critic watch --critic <name>... [--server <url>] [--since <version>] [filters] [--yes] [--dry-run]
|
|
247
|
+
[--max-batches n] [--max-images n] [--max-tokens n] [--max-cost usd] [--concurrency n] [--timeout-ms n]
|
|
248
|
+
[--spool dir] [--project slug] [--config atlas.critics.json] [--format text|json]
|
|
249
|
+
atlas critic review [--server <url>] [--critic <name>] [--state kind] [--limit n] [--list] [--non-interactive]
|
|
250
|
+
[--entry <key> ( --accept | --dismiss ) [--finding <id>]... [--note text] [--reviewer name] [--dry-run]]
|
|
251
|
+
[--project slug] [--config atlas.critics.json] [--format text|json]
|
|
252
|
+
atlas critic calibrate <name> ( --good <dir>... --bad <dir>... [--heldout-good <dir>...] [--heldout-bad <dir>...] [--state kind]
|
|
253
|
+
| --from-marks [--server <url>] [--critic-version v] ) [--out file.json] [--dry-run] [--yes]
|
|
254
|
+
[--max-images n] [--concurrency n] [--timeout-ms n] [--config atlas.critics.json] [--format text|json]
|
|
255
|
+
|
|
256
|
+
A critic is a producer: it runs here (on a laptop, in CI or in a worker), reads the catalog from an Atlas server, and publishes
|
|
257
|
+
what it thinks as layers of critiques. The server never runs a model and never holds a provider key. A critique is an opinion,
|
|
258
|
+
not a test result: it never changes whether a report passes.
|
|
259
|
+
|
|
260
|
+
Configuration is atlas.critics.json, which may be committed: it names credentials by reference (env:NAME, file:PATH) and a
|
|
261
|
+
literal credential in it is refused. The server is --server, "server.url" there, ATLAS_SERVER_URL or an https ATLAS_STORE;
|
|
262
|
+
the token is ATLAS_CRITIC_TOKEN (or ATLAS_TOKEN), never a flag, and is never sent over plain http beyond this machine.
|
|
263
|
+
|
|
264
|
+
list The critics available and configured: type, whether each is ready or needs setup, and where it sends images.
|
|
265
|
+
setup Provision a critic: fetch and verify a model checkpoint against its pinned SHA-256 (a bad checksum is an error), or
|
|
266
|
+
check that a credential reference resolves. This is the only place anything is downloaded; judging never downloads.
|
|
267
|
+
doctor Check the server is reachable, the token is accepted and has the scope a critic needs (and warn when the server is
|
|
268
|
+
open, so every caller is an administrator), that the server lists the catalog, and for each configured critic its
|
|
269
|
+
model file, dependencies, credential and provider. Each problem is reported separately, with how to fix it.
|
|
270
|
+
run Judge the entries in the chosen scope. An entry that already has a current critique of the same critic, version,
|
|
271
|
+
model, parameters and image is skipped without a call; a changed image is judged again. Failures are recorded
|
|
272
|
+
with a reason code and retried by the next run. Critiques that cannot be sent (the server went away) are kept in
|
|
273
|
+
the spool directory (default .atlas/critic-spool) and sent, byte for byte, by the next invocation.
|
|
274
|
+
--dry-run send and publish nothing: say how many entries would be judged or skipped, and where images would go
|
|
275
|
+
--yes allow sending images to a third party without asking (required without a terminal)
|
|
276
|
+
--max-images n stop cleanly after n images; --max-tokens and --max-cost likewise, from what critics report
|
|
277
|
+
--mode report (default): scores are shown and the exit code is 0; warn: also list scores below their threshold;
|
|
278
|
+
gate: exit 1 when a score is below its state kind's threshold, refused (exit 2) unless a calibration
|
|
279
|
+
with held-out evidence of this critic and version is given with --calibration
|
|
280
|
+
|
|
281
|
+
watch A worker: run in a loop over the catalog. It catches up on connecting, judges new or changed entries as they arrive (a picture
|
|
282
|
+
already judged is skipped without a call), publishes as it goes, keeps what the server cannot take and sends it next time.
|
|
283
|
+
It stops on Ctrl-C, after --max-batches batches, or when a budget (for the whole watch) is spent, and prints the version to
|
|
284
|
+
resume from (--since). It reports; it never gates. --dry-run reads the catalog once and sends and publishes nothing.
|
|
285
|
+
review The ranked "needs polish" list of one critic (lowest first) with its findings and the marks already made. With a terminal it
|
|
286
|
+
walks through the list and asks: accept (the opinion is right: the UI needs polish), dismiss (it is not), skip. With
|
|
287
|
+
--entry and --accept or --dismiss it records one decision, for the whole opinion or for --finding ids. A mark is a layer
|
|
288
|
+
under critic.review.<reviewer> (--reviewer, ATLAS_REVIEWER); it needs no more power than a critic token and never changes
|
|
289
|
+
a result, a count or the gate.
|
|
290
|
+
calibrate Judge labelled pictures (--good and --bad directories; a subdirectory's name is the state kind of the pictures in it) and/or
|
|
291
|
+
read the whole-opinion marks reviewers made (--from-marks), and measure the critic per state kind: sample sizes, precision,
|
|
292
|
+
recall, the threshold, and whether the figures are in-sample. --heldout-* pictures are never used to choose the threshold.
|
|
293
|
+
--out writes the calibration that run --calibration reads. Nothing is published.
|
|
294
|
+
|
|
295
|
+
--format json prints one document (schemas: critic-list-result, critic-setup-result, critic-doctor-result, critic-run-result,
|
|
296
|
+
critic-watch-result, critic-review-result, critic-calibrate-result).
|
|
297
|
+
A command that is wrong is {"ok":false,"error":{"message":…,"code":"usage"}} on standard error.
|
|
298
|
+
Exit codes: 0 ok, 1 the answer is no (a critic failed, a gate crossed, a problem found), 2 the command was wrong.
|
|
299
|
+
```
|
package/docs/reference/core.md
CHANGED
|
@@ -9,7 +9,7 @@ Executable statecharts: loading, composing, linting, planning and running specs
|
|
|
9
9
|
Source: `packages/core/src/cli.ts`. Import: `@crvouga/atlas/cli`
|
|
10
10
|
|
|
11
11
|
Dispatches `atlas <command>`: the statechart commands (`lint`, `plan`, `run`, `merge`, `export`) and, loaded on demand so
|
|
12
|
-
they cost nothing otherwise, `serve`, `dev`, `init` and `
|
|
12
|
+
they cost nothing otherwise, `serve`, `dev`, `init`, `report` and `critic`. Statechart configuration is `atlas.config.ts` (see
|
|
13
13
|
`defineConfig`). A command that is wrong prints a message and exits 2; a plan, lint or run that finds problems exits 1.
|
|
14
14
|
|
|
15
15
|
See docs/statecharts.md
|