Skip to content
PriceGuard

Zero runtime dependencies · 9 commands

Run it yourself

Every command in this repository, with the output it printed when we ran it. Open one to read it.

Clone, install, and check it against its own tests

Node 20 or newer. No API key, no network, no credits.

Install and run the test suite

1117 tests over the watchers, the store, the replay harness, the heal loop and the board projection, all against committed fixtures.
npm install && npm test38 lines of output

 RUN  v2.1.9 /Users/ashutosh887/Desktop/ashutosh887/priceguard

 ✓ tests/preflight.test.ts (68 tests) 6ms
 ✓ tests/brightdata.test.ts (40 tests) 25ms
 ✓ tests/watch.test.ts (58 tests) 6ms
 ✓ tests/store.test.ts (45 tests) 59ms
 ✓ tests/heal.test.ts (45 tests) 82ms
 ✓ tests/plausibility.test.ts (59 tests) 29ms
 ✓ tests/staleness.test.ts (46 tests) 43ms
 ✓ tests/archive.test.ts (97 tests) 183ms
 ✓ tests/replay.test.ts (75 tests) 26ms
 ✓ tests/heldout.test.ts (29 tests) 142ms
 ✓ tests/schema-file.test.ts (39 tests) 48ms
 ✓ tests/board.test.ts (54 tests) 18ms
 ✓ tests/job-collectors.test.ts (35 tests) 6ms
 ✓ tests/import.test.ts (25 tests) 115ms
 ✓ tests/job-store.test.ts (19 tests) 121ms
 ✓ tests/seeds.test.ts (20 tests) 8ms
 ✓ tests/classify.test.ts (13 tests) 5ms
 ✓ tests/watcher-sets.test.ts (135 tests) 57ms
 ✓ tests/join.test.ts (9 tests) 3ms
 ✓ tests/pluggable.test.ts (6 tests) 4ms
 ✓ tests/collector-create.test.ts (16 tests) 2ms
 ✓ tests/collectors.test.ts (15 tests) 4ms
 ✓ tests/real-payload.test.ts (7 tests) 5ms
 ✓ tests/site.test.tsx (83 tests) 306ms
 ✓ tests/archive-seam.test.ts (35 tests) 1040ms
   ✓ every run says where its baseline came from > names the store and the number of nights with no --archive at all 304ms
 ✓ tests/heal-cli.test.ts (16 tests) 761ms
   ✓ the command, run without --go > refuses to plan anything when no watcher has fired 312ms
 ✓ tests/live.test.ts (28 tests) 8184ms
   ✓ GET /api/status with no archive configured > reports a cluster it cannot reach as a field, never as a thrown error 8006ms

 Test Files  27 passed (27)
      Tests  1117 passed (1117)
   Start at  21:27:51
   Duration  8.87s (transform 1.22s, setup 0ms, collect 3.89s, tests 11.29s, environment 2ms, prepare 973ms)

Captured from src/site/transcripts/test.txt

The four commands the argument rests on

Each one reads committed captures. No network, no credits, no account.

Stage a break and watch both detectors read the same rows

Stages one failure shape on the newest capture, hands the identical mutated snapshot to all four watchers, and prints their verdicts side by side: status polling quiet, row-drift FIRED.
npm run watch:once -- --break rows-halved117 lines of output

  staged break: rows-halved, one retailer's rows disappear entirely
  Applied to the newest capture before either watcher reads it. Both see the same rows.

  c_msz0s41t1e9x7iko4o
  snapshot live-2026-08-23-croma~rows-halved · captured 2026-08-23T15:47:44.263Z · status ready · 0 rows
  baseline 3 nights from this disk, 2026-08-18 to 2026-08-22

  status-polling                            row-drift
  ──────────────────────────────────────    ──────────────────────────────────────
  quiet                                     FIRED
                                            
  status: ready                             zero rows on a ready snapshot. The run
  errorCode: —                              reported success and returned nothing
  errorMessage: —                           
                                            status: ready
                                            errorCode: —
                                            rowCount: 0
                                            baselineSamples: 3
                                            baselineMeanRows: 20
                                            baselineStdDevRows: 0
                                            rowsMeasured: yes
                                            nullRatesMeasured: no, 0 rows < 8

  The job reported healthy. The extraction did not. This is the case status polling cannot see.

  value-plausibility  [value-implausible]
  ────────────────────────────────────────────────────────────────────────────
  plausible

  status: ready  ·  rowCount: 0  ·  valuesMeasured: yes  ·  pricedRows: 0  · 
  comparableRows: 0  ·  uncomparableRows: 0

  row-freshness  [data-stale]
  ────────────────────────────────────────────────────────────────────────────
  fresh

  status: ready  ·  rowCount: 0  ·  priorCapture:
  scraper-run-2026-08-22T11-36-07-261Z  ·  priorCapturedAt:
  2026-08-22T11:39:09.271Z  ·  hoursSincePrior: 28.1  ·  rowsCompared: no, 0
  rows < 8

  c_msz0s665f574kacpo
  snapshot live-2026-08-23-vijay_sales~rows-halved · captured 2026-08-23T15:48:32.934Z · status ready · 0 rows
  baseline 3 nights from this disk, 2026-08-18 to 2026-08-22

  status-polling                            row-drift
  ──────────────────────────────────────    ──────────────────────────────────────
  quiet                                     FIRED
                                            
  status: ready                             zero rows on a ready snapshot. The run
  errorCode: —                              reported success and returned nothing
  errorMessage: —                           
                                            status: ready
                                            errorCode: —
                                            rowCount: 0
                                            baselineSamples: 3
                                            baselineMeanRows: 20
                                            baselineStdDevRows: 0
                                            rowsMeasured: yes
                                            nullRatesMeasured: no, 0 rows < 8

  The job reported healthy. The extraction did not. This is the case status polling cannot see.

  value-plausibility  [value-implausible]
  ────────────────────────────────────────────────────────────────────────────
  plausible

  status: ready  ·  rowCount: 0  ·  valuesMeasured: yes  ·  pricedRows: 0  · 
  comparableRows: 0  ·  uncomparableRows: 0

  row-freshness  [data-stale]
  ────────────────────────────────────────────────────────────────────────────
  fresh

  status: ready  ·  rowCount: 0  ·  priorCapture:
  scraper-run-2026-08-22T11-39-45-409Z  ·  priorCapturedAt:
  2026-08-22T11:40:33.635Z  ·  hoursSincePrior: 28.1  ·  rowsCompared: no, 0
  rows < 8

  c_msz0s7tt1xi6d8igif
  snapshot live-2026-08-23-reliance_digital~rows-halved · captured 2026-08-23T15:48:08.821Z · status ready · 0 rows
  baseline 4 nights from this disk, 2026-08-18 to 2026-08-22

  status-polling                            row-drift
  ──────────────────────────────────────    ──────────────────────────────────────
  quiet                                     FIRED
                                            
  status: ready                             zero rows on a ready snapshot. The run
  errorCode: —                              reported success and returned nothing
  errorMessage: —                           
                                            status: ready
                                            errorCode: —
                                            rowCount: 0
                                            baselineSamples: 4
                                            baselineMeanRows: 19
                                            baselineStdDevRows: 0
                                            rowsMeasured: yes
                                            nullRatesMeasured: no, 0 rows < 8

  The job reported healthy. The extraction did not. This is the case status polling cannot see.

  value-plausibility  [value-implausible]
  ────────────────────────────────────────────────────────────────────────────
  plausible

  status: ready  ·  rowCount: 0  ·  valuesMeasured: yes  ·  pricedRows: 0  · 
  comparableRows: 0  ·  uncomparableRows: 0

  row-freshness  [data-stale]
  ────────────────────────────────────────────────────────────────────────────
  fresh

  status: ready  ·  rowCount: 0  ·  priorCapture:
  scraper-run-2026-08-22T11-39-09-272Z  ·  priorCapturedAt:
  2026-08-22T11:39:45.408Z  ·  hoursSincePrior: 28.1  ·  rowsCompared: no, 0
  rows < 8

Exit codes: 0 quiet · 1 extraction break, heal it · 2 bad input · 3 implausible value, look first · 4 this capture repeats the last one, check what the URL is serving. Nightly cron uses the exit code.

See every failure shape you can stage

Every mutation id you can stage, from rows-collapsed to price-scaled-100x, the defect that actually happened here.
npm run watch:once -- --help33 lines of output
Usage: npm run watch:once -- [options]

  --break <mutation-id>   stage a break on the newest capture before any watcher reads it.
                          Every watcher gets the identical mutated snapshot, and the id is
                          named on screen so nobody mistakes it for something the site did.
  --schema <file>         measure a domain declared in a JSON schema file instead of this
                          price board, see schemas/README.md. Rows are then read as opaque
                          JSON and the schema's paths are the only claim about their shape,
                          so this also works on a collector this repo has never seen.
  --store <dir>           read captures from that store instead of snapshots/ (repo-root
                          relative). The job-board demo: --store fixtures/jobs together
                          with --schema schemas/job-board.json.
  --archive               compute the baseline from the MongoDB archive instead of this
                          disk. BASELINE_WINDOW is 7 nights, Bright Data deletes batch
                          results after 16 days and judging runs into September, so the
                          nights that define "normal" are ones the platform has already
                          deleted. Needs MONGODB_URI, and refuses rather than falling back
                          to disk.
  --help

Mutation ids (price board):
  selector-moved-price selector-moved-partial list-price-captured
  currency-vanished rows-collapsed rows-halved title-emptied stale-repeat
  ordinary-price-moves stock-churn discontinued-sku no-discount-today
  identity price-scaled-100x placeholder-price-repeated
  clearance-at-one-retailer joined-config-mismatch

Job-board ids, which need --schema schemas/job-board.json and --store fixtures/jobs:
  expired-listing-served live-listings some-listings-lapsed expiry-absent

Exit codes: 0 quiet · 1 extraction break, heal it · 2 bad input · 3 implausible value, look
first · 4 capture repeats the previous one or its validity windows have lapsed, check what
the URL is serving.

Score every watcher over the whole catalogue

Prints all three scoreboards with their synthetic-corpus warning, in about a second. Also a build gate: a block exits non-zero unless its signal beats the watchers before it and stays under a 10% false-alarm ceiling. The same numbers, as a page.
npm run replay167 lines of output
############################################################################
##                                                                        ##
##  SYNTHETIC DATA. THIS IS NOT MEASURED EVIDENCE                         ##
##                                                                        ##
##  All 10 base captures below were generated by seeded code              ##
##  (collector SYNTHETIC-DEMO). Nothing here was captured from a live     ##
##  retailer, and no page was ever loaded to produce it.                  ##
##                                                                        ##
##  These numbers show only that the replay harness runs and is           ##
##  reproducible. They say NOTHING about how the detector performs on     ##
##  real pages and must not be quoted as a result. They are replaced      ##
##  the moment real Bright Data captures exist.                           ##
##                                                                        ##
##  See fixtures/snapshots/README.md.                                     ##
##                                                                        ##
############################################################################

BLOCK 1, PRE-REGISTERED: null-rate drift vs status polling
seed 20260818 · 10 base captures · 13 mutations · 129 trials · 2026-08-23T15:58:01.174Z
  The catalogue and the two watchers as registered before any of it was measured.
  This block is frozen. Nothing added after 19 Aug appears in it.

  MUTATION                KIND    TRIALS    status-polling  row-drift
  ---------------------------------------------------------------------
  selector-moved-price    break       10              0/10      10/10
  selector-moved-partial  break       10              0/10      10/10
  list-price-captured     break       10              0/10       0/10
  currency-vanished       break       10              0/10      10/10
  rows-collapsed          break       10              0/10      10/10
  rows-halved             break       10              0/10      10/10
  title-emptied           break       10              0/10      10/10
  stale-repeat            break        9               0/9        0/9
  ordinary-price-moves    ordinary    10              0/10       0/10
  stock-churn             ordinary    10              0/10       0/10
  discontinued-sku        ordinary    10              0/10       0/10
  no-discount-today       ordinary    10              0/10       0/10
  identity                ordinary    10              0/10       0/10
  ---------------------------------------------------------------------
  BREAKS CAUGHT                                    0/79 0%  60/79 76%
  FALSE ALARMS                                     0/50 0%    0/50 0%
  ^ SYNTHETIC CORPUS (SYNTHETIC-DEMO), invented captures, not measured evidence.

  break    = a correct detector MUST fire   (counts toward breaks caught)
  ordinary = a correct detector MUST NOT fire (counts toward false alarms)

  WHAT EACH MUTATION MODELS
  selector-moved-price    price null on every row (price selector no longer matches)
  selector-moved-partial  price null on one retailer only (single-site redesign)
  list-price-captured     price holds the struck-through MRP instead of the live price
  currency-vanished       currency null on every row
  rows-collapsed          zero rows on a still-ready snapshot
  rows-halved             one retailer's rows disappear entirely
  title-emptied           title null on every row
  stale-repeat            rows repeat the previous capture verbatim (a cached template served with HTTP 200)
  ordinary-price-moves    small +/-5% price moves on a seeded subset of rows
  stock-churn             inStock flips on a minority of rows
  discontinued-sku        one or two rows drop out (end-of-life SKUs)
  no-discount-today       listPrice null on most rows (nothing on sale) while price holds
  identity                unchanged capture (control)

==============================================================================

BLOCK 2, ADDED 19 AUG: value plausibility, on shapes observed live
seed 20260818 · 10 base captures · 9 mutations · 90 trials · 2026-08-23T15:58:01.180Z
  The two defects the first live captures actually produced, plus every ordinary day
  from block 1 as a false-alarm control. Separate denominators, separate claim: these
  are breaks the null-rate detector is structurally blind to, not extra credit for it.

  MUTATION                    KIND    TRIALS    status-polling  row-drift  value-plausibility
  ---------------------------------------------------------------------------------------------
  price-scaled-100x           break       10              0/10       0/10               10/10
  placeholder-price-repeated  break       10              0/10       0/10               10/10
  clearance-at-one-retailer   ordinary    10              0/10       0/10                0/10
  joined-config-mismatch      ordinary    10              0/10       0/10                0/10
  ordinary-price-moves        ordinary    10              0/10       0/10                0/10
  stock-churn                 ordinary    10              0/10       0/10                0/10
  discontinued-sku            ordinary    10              0/10       0/10                0/10
  no-discount-today           ordinary    10              0/10       0/10                0/10
  identity                    ordinary    10              0/10       0/10                0/10
  ---------------------------------------------------------------------------------------------
  BREAKS CAUGHT                                        0/20 0%    0/20 0%          20/20 100%
  FALSE ALARMS                                         0/70 0%    0/70 0%             0/70 0%
  ^ SYNTHETIC CORPUS (SYNTHETIC-DEMO), invented captures, not measured evidence.

  break    = a correct detector MUST fire   (counts toward breaks caught)
  ordinary = a correct detector MUST NOT fire (counts toward false alarms)

  WHAT EACH MUTATION MODELS
  price-scaled-100x           one retailer's prices are 100x too large (a decimal point was eaten)
  placeholder-price-repeated  one retailer returns a single hard-coded price for every SKU
  clearance-at-one-retailer   one retailer clears stock at 50-65% off (a real sale, not a defect)
  joined-config-mismatch      one SKU is joined to a higher-spec variant at one retailer (~2x, both correct)
  ordinary-price-moves        small +/-5% price moves on a seeded subset of rows
  stock-churn                 inStock flips on a minority of rows
  discontinued-sku            one or two rows drop out (end-of-life SKUs)
  no-discount-today           listPrice null on most rows (nothing on sale) while price holds
  identity                    unchanged capture (control)

==============================================================================

BLOCK 3, the repeated capture: what a summary of the past cannot see
seed 20260818 · 10 base captures · 6 mutations · 59 trials · 2026-08-23T15:58:01.195Z
  A cached or not-found template served with HTTP 200: tonight's timestamp, last night's
  rows, verbatim. Every field populated, every value real, the job green. The three
  watchers above judge (snapshot, baseline statistics) and a baseline is a summary, so
  none of them is ever shown the rows that are the only evidence. Same ordinary days as
  the control, because a rule this narrow is worth nothing without them.

  MUTATION              KIND    TRIALS    status-polling  row-drift  value-plausibility  row-freshness
  ------------------------------------------------------------------------------------------------------
  stale-repeat          break        9               0/9        0/9                 0/9            9/9
  ordinary-price-moves  ordinary    10              0/10       0/10                0/10           0/10
  stock-churn           ordinary    10              0/10       0/10                0/10           0/10
  discontinued-sku      ordinary    10              0/10       0/10                0/10           0/10
  no-discount-today     ordinary    10              0/10       0/10                0/10           0/10
  identity              ordinary    10              0/10       0/10                0/10           0/10
  ------------------------------------------------------------------------------------------------------
  BREAKS CAUGHT                                   0/9 0%     0/9 0%              0/9 0%       9/9 100%
  FALSE ALARMS                                   0/50 0%    0/50 0%             0/50 0%        0/50 0%
  ^ SYNTHETIC CORPUS (SYNTHETIC-DEMO), invented captures, not measured evidence.

  break    = a correct detector MUST fire   (counts toward breaks caught)
  ordinary = a correct detector MUST NOT fire (counts toward false alarms)

  WHAT EACH MUTATION MODELS
  stale-repeat          rows repeat the previous capture verbatim (a cached template served with HTTP 200)
  ordinary-price-moves  small +/-5% price moves on a seeded subset of rows
  stock-churn           inStock flips on a minority of rows
  discontinued-sku      one or two rows drop out (end-of-life SKUs)
  no-discount-today     listPrice null on most rows (nothing on sale) while price holds
  identity              unchanged capture (control)

==============================================================================

BLOCK 4, ADDED 22 AUG: the expiry signal, where the schema carries a validity date
seed 20260818 · 10 base captures · 4 mutations · 40 trials · 2026-08-23T15:58:01.200Z
  Staged on a synthetic job-board corpus, the one domain here whose rows carry their own
  expiry (`validThrough`). Every dated posting's window closed while the page still serves
  them: proof from a single capture that the bytes are old, needing no history, which is why
  the freshness rule above cannot make the same call. The other four run so their zero column
  is visible. Ordinary days are the job board's own: a current board, the lazy-purge lag that
  makes firing on any expired row unusable, and a board that publishes no expiries at all.

  MUTATION                KIND    TRIALS    status-polling  row-drift  value-plausibility  row-freshness  row-expiry
  --------------------------------------------------------------------------------------------------------------------
  expired-listing-served  break       10              0/10       0/10                0/10           0/10       10/10
  live-listings           ordinary    10              0/10       0/10                0/10           0/10        0/10
  some-listings-lapsed    ordinary    10              0/10       0/10                0/10           0/10        0/10
  expiry-absent           ordinary    10              0/10       0/10                0/10           0/10        0/10
  --------------------------------------------------------------------------------------------------------------------
  BREAKS CAUGHT                                    0/10 0%    0/10 0%             0/10 0%        0/10 0%  10/10 100%
  FALSE ALARMS                                     0/30 0%    0/30 0%             0/30 0%        0/30 0%     0/30 0%
  ^ SYNTHETIC CORPUS (SYNTHETIC-JOBS), invented captures, not measured evidence.

  break    = a correct detector MUST fire   (counts toward breaks caught)
  ordinary = a correct detector MUST NOT fire (counts toward false alarms)

  WHAT EACH MUTATION MODELS
  expired-listing-served  every dated posting's validity has already ended (a cached board served with HTTP 200)
  live-listings           every dated posting expires weeks ahead (a healthy, current board)
  some-listings-lapsed    a minority of dated postings expired while still listed (ordinary board lag)
  expiry-absent           no posting carries validThrough (the board does not publish expiries)

PASS (block 1): row-drift caught 60/79 breaks vs 0/79 for status-polling, false alarms 0%.
PASS (block 2): value-plausibility caught 20/20 of the live shapes that row-drift scored 0/20 on, false alarms 0% over 70 ordinary days.
PASS (block 3): row-freshness caught 9/9 repeated captures that the other three scored 0/9 on, false alarms 0% over 50 ordinary days.
PASS (block 4): row-expiry caught 10/10 lapsed boards with no history that the other four scored 0/10 on, false alarms 0% over 30 ordinary days.

Exit codes: 0 pass · 1 a detector missed its claim or cried wolf · 2 bad input.

Serve the real board from the committed captures

Serves /board on localhost from the three unedited live captures. Add --html to print it to stdout instead.
npm run board -- --root fixtures/live3 lines of output
PriceGuard, http://127.0.0.1:4173/
  21 SKUs · 56/63 cells confirmed by their retailer's last run · 3 stale · 0 never confirmed · newest capture 2026-08-23T15:48:08.823Z
  Ctrl-C to stop. Refresh the page after a new capture lands.

Check the repository's own precautions

17 checks that encode the mistakes this project already made: no credential tracked by git, docs/ untracked, the fixtures a measured claim rests on present, and the sponsor's quotation diffed byte-for-byte against the shipped package's README.
npm run preflight45 lines of output

preflight . Would this repo survive being handed to a judge right now?

  pass  No credential is tracked by git
        scanned 266 tracked text files
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  The internal docs/ folder is not tracked
        0 tracked paths under docs/
  pass  Fixtures a measured claim rests on are in the clone
        58 fixture snapshots tracked
  pass  Every reported count says where it came from
        every markdown file reporting counts states its provenance
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  The sponsor is quoted verbatim
        byte-for-byte against @brightdata/cli@0.3.5's own README
  pass  `dependencies` in package.json is empty
        0 runtime dependencies; optional: mongodb
  pass  Only src/archive/ and src/cli/archive.ts import `mongodb`
        src/archive/** and src/cli/archive.ts only
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  Outside src/archive/, the archive is only imported dynamically or as a type
        every reference outside the archive is type-only or dynamically loaded
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  Nothing reachable from `npm run build` imports the archive
        81 modules reachable from src/cli/site.ts, none under src/archive/
  pass  Every `npm run` command in the README exists in package.json
        15 commands named, all present
  pass  Every reference pins @brightdata/cli@0.3.5
        15 references, all @0.3.5
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  No code path uses --legacy-output
        0 occurrences under src/
        exempt as declared counterexamples: tests/preflight.test.ts
  pass  Every .env key is documented in .env.example
        7 keys documented
  pass  The README names the command that regenerates its number
        README.md cites `npm run replay`
  pass  No unfilled placeholder is left in the README
        grep for `<!-- [A-Z_]* -->` returns nothing
  pass  The test count in the README matches the suite
        README says 1117 tests, and so does `npm test`
  pass  Committed transcripts still say what the commands say
        every transcript count agrees with the 1117-test suite

clean, 17 checks, nothing to fix.

Captured from src/site/transcripts/

The two commands that can spend credits, and the one that cannot

Scraper Studio bills per page load.

Both credit-spending commands are dry by default

npm run capture and npm run heal print the plan and its cost, and do nothing until you add --go. Both need BRIGHTDATA_API_KEY in .env. The transcripts below are their built-in help, because a real capture here would spend credits to illustrate a web page.

Run the collectors and store the envelopes

Prints what it would capture and what it would cost, and stops. With --go it runs each collector in collectors.json and writes the raw envelope to disk before a byte is parsed.
npm run capture9 lines of output
Usage: npm run capture -- [options]

  --go                  actually run the collectors. Without it this prints the plan and
                        what it would cost, and spends nothing.
  --only <retailer>     capture one collector (default: every collector in collectors.json)
  --label <text>        prefix for the stored snapshot ids, e.g. --label baseline-03
  --help

Exit codes: 0 ok · 1 nothing matched --only · 2 no API key configured.

Detect, prompt, review the diff, approve

Read the stored evidence, build the heal prompt, stop at awaiting_approval, show preview_result and diff_summary, then approve with --auto-save. The repair that actually ran.
npm run heal -- --collector c_msz0s7tt1xi6d8igif26 lines of output
Usage: npm run heal -- [options]

  --root <dir>           snapshot store root (default: snapshots/, falling back to
                         fixtures/snapshots/ when no real capture exists yet)
  --collector <id>       collector to heal (default: BRIGHTDATA_COLLECTOR_ID, or the
                         only collector in the store)
  --window <n>           baseline window in snapshots (default: 7)
  --prompt <text>        send this instead of the prompt built from the evidence
                         (still capped at 1000 chars)
  --max-page-loads <n>   refuse to start if the loop could bill more than this
  --timeout <n>          polling timeout in seconds; a heal runs into the minutes
  --force                heal even though the watcher is quiet, you are paying to
                         repair something nothing has reported as broken
  --auto-approve         skip the gate. Costs you the diff entirely: the platform
                         attaches preview_result only to an awaiting_approval envelope
  --go                   actually run it. Without this nothing is invoked, nothing is
                         billed, and no template is touched
  --archive              compute the baseline from the MongoDB archive instead of this
                         disk. BASELINE_WINDOW is 7 nights, Bright Data deletes batch
                         results after 16 days and judging runs into September, so the
                         nights that define "normal" are ones the platform has already
                         deleted. Needs MONGODB_URI, and refuses rather than falling back
                         to disk.
  --help

Exit codes: 0 planned or healed · 1 rejected, not fixed, or failed · 2 bad input or refused.

Turn run envelopes into a snapshot store

Reads any *.json in a directory of Bright Data run envelopes into the local store the watchers and the board read.
npm run import9 lines of output
Usage: npm run import -- [options]

  --from <dir>   captures to read (default: docs/runs when it exists, else examples)
  --to <dir>     snapshot store to write (default: snapshots)
  --help

Any *.json in the directory is read. Spends no credits.

Exit codes: 0 ok · 2 bad input.

Captured from src/site/transcripts/