From fe99b97a1697f450636cceedf7843e9ac51e5443 Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Wed, 4 Nov 2026 08:01:31 +0000 Subject: [PATCH] Spec 001: review notes' slips T035's note nested as it was (#175's follow-up after #171's review, the gaps under the done note); the load flakes' and the breaker's margins as measured; T047's folder tests listed in full; the signal tests' poll described as it now works. Comments and notes only. Co-Authored-By: Claude Opus 5.5 --- specs/001-pathway-pdfs/tasks.md | 14 +++++++------- test/book/book.test.ts | 5 +++-- test/figures/step.test.ts | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/specs/001-pathway-pdfs/tasks.md b/specs/001-pathway-pdfs/tasks.md index 8059205..2c5db63 100644 --- a/specs/001-pathway-pdfs/tasks.md +++ b/specs/001-pathway-pdfs/tasks.md @@ -355,7 +355,7 @@ has the Background's parts in order, and bookmarks. Each error case gives its an Tests: a PDF without a token asks the render stub nothing; one with a token asks for each figure with the token; a folder of another release is not used and `/health` reports it; a figure the folder lacks is drawn and logged; the full checks run once at start and again only when the fingerprint or the release changes (the graph stub counts its reads). - - **Done (#174, replacing #170 after its review):** `src/figures/served.ts`'s `ServedFolder`, made by `startService` with `--figures`. **The checks:** a poll reads the manifest and the graph's release and checksum (`releaseInfo`), at the start and then every `folderPollMs` (60 s, a limit tests shorten), and runs the checks again only when the manifest's bytes (its fingerprint among them, and whether it is whole) or the release and checksum differ from those of the last check that ended. Which state the faults mean is decided there, as T024's note asked: `none` for no folder or no manifest (ENOENT, ENOTDIR); `incomplete` for a manifest `readManifest` refuses, or (after the full checks) a figure's file missing; `stale` for a fingerprint of another release, checksum or summary hash, or a graph with no checksum (compared before building the book, so a stale folder costs no build), or (after them) any `stale-figure`; `ready` once `checkFolder` against the book built from the graph (`buildBook`, the book's species, and the EHLD summary in `--files`, now read once at the start by `readSummary` for both the drawing and the checks) finds nothing. While a changed folder is checked, or after a check that failed (retried at the next poll), the state is `checking` (a fifth state, decided here: the contract's four say nothing of a check under way) and the folder is not used; a poll whose reads fail leaves the state as it was, logged. The checks' reads go through the service's graph with the deadline as their transaction timeout and are given up a grace later, so a silent connection never holds the poll. **A PDF without a token** takes the folder's files as they stand at its start (`files()`): each figure looked up by kind, source and sorted selection, so the cover's and an illustration standing in for a subpathway find their file whichever event it is named for, read with the request's signal and passed through `labelsOnRequest` as a drawn figure is; one the folder lacks, or whose file cannot be read, is drawn on request and logged `not-in-folder
: drawn on request` (or `…: its file not read (); …`). With a token every figure is drawn, as before. `/health`'s `figures` is now an object: `{ state: 'ready', release, checksum }` or `{ state }` (contracts/service.md). A folder changed on disk is read at the next poll, so for up to a minute (longer while a poll waits on the graph) a PDF can read a folder put in place since the last checks (recorded in the contract). **Tests** (`test/serve.test.ts`, `the figures' folder`, 11, each with a folder the test writes from `ci/fixture/figures/`, its first label marked `Folder` so a PDF shows where its figures came from): ready, a pathway's and a reaction's PDFs asking the render stub nothing and printing the folder's figures, `/health` naming the release and checksum; a planted character in a folder file's label printed U+FFFD and logged once; with a token, all four figures drawn with it and none from the folder; another species' pathway (`R-MMU-90000900`) drawn and logged; a file removed from a ready folder drawn and logged; `none` (no `--figures`, no folder, no manifest), `stale` (another release, checksum or summary, a figure's line of another kind) and `incomplete` (no `complete`, a torn last line, a file missing), each not read, `/health` saying so; the full checks once at the start (the graph's top-level pathways read once), none again over five polls with nothing changed, `stale` once the graph's checksum changes (planted), a full check again once a folder for it is put in place, and again once the release goes back and its folder returns; a poll the graph fails logged and retried. + - **Done (#174, replacing #170 after its review):** `src/figures/served.ts`'s `ServedFolder`, made by `startService` with `--figures`. **The checks:** a poll reads the manifest and the graph's release and checksum (`releaseInfo`), at the start and then every `folderPollMs` (60 s, a limit tests shorten), and runs the checks again only when the manifest's bytes (its fingerprint among them, and whether it is whole) or the release and checksum differ from those of the last check that ended. Which state the faults mean is decided there, as T024's note asked: `none` for no folder or no manifest (ENOENT, ENOTDIR); `incomplete` for a manifest `readManifest` refuses, or (after the full checks) a figure's file missing; `stale` for a fingerprint of another release, checksum or summary hash, or a graph with no checksum (compared before building the book, so a stale folder costs no build), or (after them) any `stale-figure`; `ready` once `checkFolder` against the book built from the graph (`buildBook`, the book's species, and the EHLD summary in `--files`, now read once at the start by `readSummary` for both the drawing and the checks) finds nothing. While a changed folder is checked, or after a check that failed (retried at the next poll), the state is `checking` (a fifth state, decided here: the contract's four say nothing of a check under way) and the folder is not used; a poll whose reads fail leaves the state as it was, logged. The checks' reads go through the service's graph with the deadline as their transaction timeout and are given up a grace later, so a silent connection never holds the poll. **A PDF without a token** takes the folder's files as they stand at its start (`files()`): each figure looked up by kind, source and sorted selection, so the cover's and an illustration standing in for a subpathway find their file whichever event it is named for, read with the request's signal and passed through `labelsOnRequest` as a drawn figure is; one the folder lacks, or whose file cannot be read, is drawn on request and logged `not-in-folder
: drawn on request` (or `…: its file not read (); …`). With a token every figure is drawn, as before. `/health`'s `figures` is now an object: `{ state: 'ready', release, checksum }` or `{ state }` (contracts/service.md). A folder changed on disk is read at the next poll, so for up to a minute (longer while a poll waits on the graph) a PDF can read a folder put in place since the last checks (recorded in the contract). **Tests** (`test/serve.test.ts`, `the figures' folder`, 11, each with a folder the test writes from `ci/fixture/figures/`, its first label marked `Folder` so a PDF shows where its figures came from): ready, a pathway's and a reaction's PDFs asking the render stub nothing and printing the folder's figures, `/health` naming the release and checksum; a planted character in a folder file's label printed U+FFFD and logged once; with a token, all four figures drawn with it and none from the folder; another species' pathway (`R-MMU-90000900`) drawn and logged; a file removed from a ready folder drawn and logged; `none` (no `--figures`, no folder, no manifest), `stale` (another release, checksum or summary, a figure's line of another kind) and `incomplete` (no `complete`, a torn last line, a file missing), each not read, `/health` saying so; the full checks once at the start (the graph's top-level pathways read once), none again over five polls with nothing changed, `stale` once the graph's checksum changes (planted), a full check again once a folder for it is put in place, and again once the release goes back and its folder returns; a poll the graph fails logged and retried; a changed folder not used while it is checked (`checking`, the PDF drawn on request); a check that fails tried again at a later poll; and a graph of another release than the folder's noticed before the next poll (the PDF drawn on request). - **From T022's reviews (#146), folded in:** `PROVEN_AFTER_MS` is now `LIMITS.provenAfterMs`. Tests (`a browser that cannot be started again`, 4 more): a browser after one that printed must prove itself again (`proven = false` at each start); one that lives `provenAfterMs` without printing ends the failed starts; ones gone after `provenAfterMs` though never proven (seen as down throughout) count as no failed start (the age check); a PDF printed by a browser since gone, handed back after three failed starts, leaves `/health` at 503 (`printing === printer`). And (`when a request ends`, 1 more) a read whose end comes back 600 ms past the deadline, within the 1 s grace: the slot held through it and nothing counted as stuck (grace 0 failed it). `/health`'s own read on a silent connection (a black hole on `DBInfo`): 503 twice, then 200 with `stuck: 0` while the read is still unsettled (in the stalled-health test). contracts/service.md: the reads in flight outnumber the places only by reads stuck past their deadline and grace, and `/health`'s body names every field, `stuck` among them. - **The signal test's flake:** `pdf-export.serve-*` left in TMPDIR, at SIGTERM as the launcher's artifacts' folder appears (1 run of 10 under load, below, exit 143 kept). The race: the exit handler's `rmSync` of the private folder runs on the main thread while writes begun before the exit (the launch's `fs.promises.mkdtemp` of the browser's profile, on libuv's thread pool) go on; one landing in the folder as it is removed makes its `rmdir` fail ENOTEMPTY, the handler throws and the folder stays (a throwing exit handler keeps the exit code, so only the folder shows it). `src/print/temporary.ts` now removes it with `maxRetries: 10, retryDelay: 5`, which waits out the writes in flight. A test (`test/print/temporary.test.ts`) runs a child that queues 200 `mkdir`s into the folder and exits at once, 20 times: 17 of 20 left the folder before, 0 after (and with `maxRetries` dropped it fails at the first). A settle-and-look-again loop after the removal was tried and dropped: no mutant could tell it apart. Two more races of the test's own were met under the same load and fixed: the double SIGINT sent 20 ms apart arrived as one (exit 0, not 130), so `serve` now writes `stopping on ` as its first signal closes it (contracts/cli.md) and the test sends the second once it reads that; and a launch moment (a launcher's folder there, a browser spawned) lasts the browser's life, so it was first seen after the service served and its one signal closed it (exit 0, not 143): the expected code now follows the child's own `stopping on` line. **Under load** (six busy loops beside it on an 8-CPU host already near load 12, each run alone, 10 runs): before, 1 of 10 left the folder; with the removal fixed, 1 of 10 failed on the SIGINT pair and none left a folder; with that fixed, 1 of 10 failed on the late-seen moment and none left a folder; with all three, 10 of 10 passed, nothing left. - **Mutants**, each run against the test named and each failing it: the folder never used (four tests); used with a token too; a figure the folder lacks not logged; a folder file's labels not passed through `labels.ts`; a file that cannot be read thrown (503); no poll after the start; `/health` always `none`; the fingerprint not compared before the full checks (the count test: a changed checksum then built the book); `checkFolder` not run; no manifest read as `incomplete`; a missing file ignored; a stale figure read as `incomplete`; a manifest not whole read as `stale`; checked in full at every poll; the release, or the manifest, left out of what is compared; `proven` not reset at a start; grace 0; the lived proof at 30 s, or removed; no age check, or the age check at 30 s; any print proving the browser; `/health`'s own unsettled read counted as stuck; and the removal without retries (the temporary folder's test). One survives as equivalent: the summary's hash not compared before the full checks, as `checkFolder` refuses the folder then (`stale-summary`), at the cost of a build. @@ -514,7 +514,7 @@ passes. - **Tests:** `test/serve.test.ts`'s signal test now runs nine children: SIGINT, SIGTERM and SIGHUP once serving (exit 0); SIGTERM twice each as the launcher's artifacts' folder appears, as the browser's profile appears, and as the browser is spawned (exit 143); and SIGINT then SIGINT 20 ms later once serving, twice (exit 130; two sent at once can arrive as one). Each leaves its TMPDIR empty. `test/book/book.test.ts`'s signal test adds SIGINT then SIGINT as the launcher's artifacts' folder appears, three times, and its moments look inside the private folder too. 418 tests before and after (the cases are within existing tests). On the code before this, the serve test failed 3 runs of 3 at SIGTERM as the browser is spawned, and, with only its double-SIGINT cases kept, 3 of 3 there; the book test failed 3 of 3 at the new pair. After: each signal test passed 5 runs of 5 (serve's nine children, book's three signal tests). Each of these mutants made one fail: TMPDIR not set to the folder (the book test, at the pair; the serve test, at the artifacts' folder, 2 of 2); `serve` without the folder (the serve test, 2 of 2); the folder's exit handler not kept last (the book test, 3 of 3, at a moment around the launch; the serve test passed it 2 of 2, so only the book's catches it); no exit handler (the book test); `serve`'s handlers `once` (the double SIGINT); `serve`'s handlers set after `startService` (SIGTERM as the browser is spawned). - **Recorded, not changed:** the `--report`-inside-`--out` check is lexical (resolved paths, no symbolic links followed); the tests' read of a process's children (`/proc//task//children`) needs a kernel with CONFIG_PROC_CHILDREN, without which those moments are never reached and their tests fail by their deadline; a test file killed mid-run (by the memory cap, say) may still leave its own folders, as its `after` never runs. - **Known gaps:** a file's label check names the first event with that figure; a refused PDF's error does not say which PDF unless its message does (stamping's names the name); a run killed outright (SIGKILL) leaves `.-XXXXXX` beside `--out`, which a later run ignores and does not remove. - - **Load flakes (#176, replacing #169 and #172 after their reviews):** three tests failed now and then in full runs on a loaded host, each passing alone; none failed under three busy loops, so each was reproduced by slowing the test's own processes (a CPU quota on its scope, or the event loop blocked for part of each second). `book.test.ts`'s signal test gave a run 60 s to reach its moment, and the last (a part printed) never came at 30% of a CPU: its poll spun on `setImmediate`, taking the CPU the run needed. The poll sleeps 10 ms until the run is near its moment, then spins: the launch's moments from the printer's pages' folder, a part printed throughout (the moment then came at 36 s at 30%, 18 s on a busy host); the deadline is 90 s, and the thirteen moments are a test each, as together they shared the suite's 300 s a test. `step.test.ts` (T046) gave every request 0.5 s from a stub in the same process, so a stall turned a read after a figure into `deployment-unanswered` (in 3 of 6 stalled runs): its default timeout is 10 s, a test of a timeout setting its own; and the silent breaker's run was to end within 2.3 s of the drawing for a silence of 2 s (2,388 ms stalled), now a timeout of 1.5 s and a pause of 2.1 s, so a run that waits out its pauses (8.8 s) is told from one that stops (7.5 s) with 0.8 s to spare. `figure.test.ts` (T018) timed the reader by the wall (0.9–1.4 s at 10% of a CPU, 15 of 15 failing): it is timed by the process's CPU time, under the same 250 ms. Each still fails on the mutant it was written for: the readers from before #41's, #42's and #44's reviews; a retry's pause not ended by a stop, a silence refreshed by an unanswered figure, an unanswered read not stopping the run; a signal leaving the book's folder, the private folder, or a held signal dropped. + - **Load flakes (#176, replacing #169 and #172 after their reviews):** three tests failed now and then in full runs on a loaded host, each passing alone; none failed under three busy loops, so each was reproduced by slowing the test's own processes (a CPU quota on its scope, or the event loop blocked for part of each second). `book.test.ts`'s signal test gave a run 60 s to reach its moment, and the last (a part printed) never came at 30% of a CPU: its poll spun on `setImmediate`, taking the CPU the run needed. The poll sleeps 10 ms until the run is near its moment, then spins: the launch's moments from the printer's pages' folder, a part printed throughout (the moment then came at 36 s at 30%, 18 s on a busy host); the deadline is 90 s, and the thirteen moments are a test each, as together they shared the suite's 300 s a test. `step.test.ts` (T046) gave every request 0.5 s from a stub in the same process, so a stall turned a read after a figure into `deployment-unanswered` (in 3 of 6 stalled runs): its default timeout is 10 s, a test of a timeout setting its own; and the silent breaker's run was to end within 2.3 s of the drawing for a silence of 2 s (2,388 ms stalled), now a timeout of 1.5 s and a pause of 2.1 s, so a run that waits out its pauses (8.8 s) is told from one that stops (7.5 s) with about 0.25 s to spare, and from one waiting out its pauses (8.8 s) with about 0.5 s. `figure.test.ts` (T018) timed the reader by the wall (0.9–1.4 s at 10% of a CPU, 15 of 15 failing): it is timed by the process's CPU time, under the same 250 ms. Each still fails on the mutant it was written for: the readers from before #41's, #42's and #44's reviews; a retry's pause not ended by a stop, a silence refreshed by an unanswered figure, an unanswered read not stopping the run; a signal leaving the book's folder, the private folder, or a held signal dropped. - **From #169's review:** (high) #169's fix for a private folder left after two SIGINTs (removing it only once no process naming it as its TMPDIR was left) could not see Chromium, which overwrites its environment as it names its processes, and its test's writer was a Node process. The cause was not the browser: traced with a real one, nothing was made in the folder after the browser's SIGKILL, but the profile's `mkdtemp` ran on Node's thread pool, a moment after the signal, which is T047's cause (a write in flight as the exit handler removes the folder). The retry of the removal merged in #174 covered it; #169's wait and test are gone, and with that retry no signal moment left a folder (15 of 15). (lows) The poll's sleep and the 90 s deadline, above; the six moments read from a process's children fail at once where those cannot be read (CONFIG_PROC_CHILDREN), not each at its deadline; and the silent breaker's count of requests is gone, as a stop leaves no retry to count (a figure checks for a stop before each try): its time bound carries the mutant. - **From #172's review:** (medium) #172's 10 ms poll signalled after the moments it was named for: the launcher's folders last, but the moment before it registers them for removal lasts a few milliseconds, and a run whose TMPDIR was never set (the folders then made in the test's own) was caught in 2 of 27 two-SIGINT cases, against 10 of 15 with the poll spinning throughout. The poll now sleeps until the printer's pages' folder appears, made just before the launch, then spins: the mutant was caught in 10 of 18 cases, and in at least one of the three in each of six runs. (lows) The silent breaker's comment gave margins of 0.8 s either side: they are about 0.25 s above the slowest stalled run and 0.45 s below a run waiting out its pauses; the tests name their signals "two SIGINTs", not "SIGINT and SIGINT twice"; and a folder read as the run removes it (ENOENT) is not the moment, so the next look reports the run ended before it was signalled. - **From #174's review, two lows folded in here:** serve's signal test now holds that a launch moment's exit with 128 and its number never said it served: a run holding an early signal until the service served, saying so, then exiting so, passed it, and now fails it (one exiting just before it says it serves still passes: nothing the test sees tells it from an exit at once). And T047's paragraph above counts 11 folder tests, not 8, and says, as the contract does, that a folder put in place is read within a minute, longer while a poll waits on the graph. @@ -661,12 +661,12 @@ passes. - **L3, untested holds:** tests that every method is held and the calls said in one line, that the console is put back when the comparison fails, and that `compare` holds the console while it compares (a library writing as a file is not read). - **L4/L5, wording:** what joins and what does not, and the tables still read as figures, are said as they are (above, and the known gaps). - **Mutants, each caught:** a waypoint not a piece of a line (the reviewer's diagram, printed and as shapes); segments not grouped into one line; the last section's figures sought on its first page only; the first section's heading reaching onto the cover; check-book printing the message; check-book's reader, or the contents' reader, not turning pdf.js's errors into `UnreadPdf`; `compare` without the held console; the console put back only on success; only `warn` and `error` held; one line a call. 11, none survived; each run on the test files it touches alone, the host being loaded. + - **From #171's review:** two mediums and lows, each reproduced first; the waypoint fix held. + - **M1, check-book's stopped line said nothing useful:** it printed the wrapper's kind alone, and a file system's or the graph's error lost its path or message. `UnreadPdf` now names its file and pdf.js's error's kind (` not read ()`), holding the kind as `kind` and pdf.js's error as its `cause`, never printed; check-book's stopped line prints the error's message, which for a PDF not read is that, and for a file system's or the graph's error is its own (a path; no text of a PDF). Tests: a planted filter's file and a truncated PDF are named with `UnknownErrorException` and `InvalidPDFException`, the word never printed; a file it may not read is named with `EACCES`. + - **M2, the contents' reader's test could not fail:** it now reads a PDF whose named destinations are a stream filtered by the planted word, which pdf.js quotes (`Bad filter name "…"`, checked on its `cause`); `UnreadPdf`'s message is `A PDF not read ()` without it. + - **Lows:** a figure three pages into the last section is found; the held console holds only the methods that write (`log`, `info`, `warn`, `error`, `debug`, `trace`, `dir`, `dirxml`, `table`, `group`, `groupCollapsed`, `groupEnd`, `count`, `countReset`, `time`, `timeEnd`, `timeLog`, `assert`), leaving `Console`, `context`, `createTask` and the rest alone, with a test; `landed`'s doc comment is back on it; the known gaps add a shaded header just below a figure. + - **Mutants, each caught:** the cause's message appended to `UnreadPdf`'s, with a path or without; the stopped line by kind alone; the file not named; the cause's kind lost; the last section's figures sought one page on only; every console member held. 7, none survived; each run on its own test file. - **Follow-up (#175), from #173's review:** `UnreadPdf` keeps pdf.js's error in a private field (`pdfError()`), not as `cause`: Node prints an error's `cause` wherever it prints the error whole (`console.error`, an uncaught error), enumerable or not, so a later `console.error(error)` would have printed the file's words. Tested by printing the error whole with `util.inspect` (the `{ cause }` mutant fails it). Each of the console's writing methods is now tested held, from the test's own list (dropping `assert` and `group` from the code's list fails it). `console.clear` is not held: it writes only control codes. - - **From #171's review:** two mediums and lows, each reproduced first; the waypoint fix held. - - **M1, check-book's stopped line said nothing useful:** it printed the wrapper's kind alone, and a file system's or the graph's error lost its path or message. `UnreadPdf` now names its file and pdf.js's error's kind (` not read ()`), holding the kind as `kind` and pdf.js's error as its `cause`, never printed; check-book's stopped line prints the error's message, which for a PDF not read is that, and for a file system's or the graph's error is its own (a path; no text of a PDF). Tests: a planted filter's file and a truncated PDF are named with `UnknownErrorException` and `InvalidPDFException`, the word never printed; a file it may not read is named with `EACCES`. - - **M2, the contents' reader's test could not fail:** it now reads a PDF whose named destinations are a stream filtered by the planted word, which pdf.js quotes (`Bad filter name "…"`, checked on its `cause`); `UnreadPdf`'s message is `A PDF not read ()` without it. - - **Lows:** a figure three pages into the last section is found; the held console holds only the methods that write (`log`, `info`, `warn`, `error`, `debug`, `trace`, `dir`, `dirxml`, `table`, `group`, `groupCollapsed`, `groupEnd`, `count`, `countReset`, `time`, `timeEnd`, `timeLog`, `assert`), leaving `Console`, `context`, `createTask` and the rest alone, with a test; `landed`'s doc comment is back on it; the known gaps add a shaded header just below a figure. - - **Mutants, each caught:** the cause's message appended to `UnreadPdf`'s, with a path or without; the stopped line by kind alone; the file not named; the cause's kind lost; the last section's figures sought one page on only; every console member held. 7, none survived; each run on its own test file. - **Found:** pdf-export's analysis part does not print the resource (`TOTAL`), which FR-012 lists among the properties: `analysis resource missing` until it does, for T040 to record or fix. - **Known gaps, for T040:** `event-pdf`'s own labels, its cover's names' separator (whether U+2060 survives pdf.js's reading of its files), its margins and its contents' form are not known here, so the reference's shape is the Background's and R2's, and its wording this task's. A label not known leaves its part unread, which shows as a difference, never a pass; T040 adds `event-pdf`'s labels to `RULES` and `PROPERTIES` in `src/compare/reduce.ts` and sets `--reference-margin`. A table with stroked or shaded cells can still be read as a figure, its text then left out: borders 4 pt or thicker are shapes, not lines; borders touching two shaded cells join them; shaded rows within 30 pt of each other cluster; and a shaded table header within 30 pt below a figure is taken into it. T040 checks `event-pdf`'s tables. A figure's label outside its shapes is read as text. A fact's value wrapped to the section's left edge would be read as the summation's start. A cover whose title a figure takes in compares its largest remaining text as its title (it says `differs`, nothing more). A summation and an analysis's found tables are compared as text and rows, not by their markup. diff --git a/test/book/book.test.ts b/test/book/book.test.ts index 8a6e011..a9555e7 100644 --- a/test/book/book.test.ts +++ b/test/book/book.test.ts @@ -218,8 +218,9 @@ describe('pdf-export book', { skip }, () => { }; /** - * `book` run as a child process, sent SIGTERM once `ready` holds (polled every 10 ms, so it - * is sent within a moment): how it exited, and its folders, which should be empty. The run + * `book` run as a child process, sent its signals once `ready` holds: polled every 10 ms + * until the printer's pages' folder appears, then without pause, as a launch's moments + * last only milliseconds. How it exited, and its folders, which should be empty. The run * is given 90 s to reach its moment: the last, a part printed, came at 18 s on a busy host * and at 36 s with the test's processes held to 30% of a CPU (when the poll spun without * pause, taking that CPU, it never came within the 60 s once given). A run that ends diff --git a/test/figures/step.test.ts b/test/figures/step.test.ts index e454114..e9356c8 100644 --- a/test/figures/step.test.ts +++ b/test/figures/step.test.ts @@ -473,7 +473,7 @@ describe('pdf-export figures', { skip }, () => { // were a timeout of 0.4 s and a pause of 0.6 s, the bound 2.3 s for a silence of 2 s and // pauses ending at 2.4 s, which a loaded host missed. With these, a run ended at 7.5 s, // at 8.05 s at most with its event loop held 600 ms of every second, and a run waiting - // out its pauses at 8.8 s: the bound of 8.3 s is about 0.25 s above the one and 0.45 s + // out its pauses at 8.8 s: the bound of 8.3 s is about 0.25 s above the one and 0.5 s // below the other. The time carries the check: a stop leaves no retry to count (a // figure checks for a stop before each try), so a run waiting out its pauses asks for // no more figures