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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions specs/001-pathway-pdfs/contracts/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,13 @@ the figures already drawn by `figures`.
here can come after earlier parts or PDFs are printed; the step still ends with exit
1 and no book written, the folder being moved into place only at the end.
- **Exit 0:** the book is written, and `check-book` passed on it. The folder is written
beside its name and moved into place, so a failed run never leaves a partial book. A
run is whole: a failure in any PDF writes none, and the step is run again.
- **Exit 1:** a fault from the preflight or FR-011. The report names each one by stable
identifier or file name, never a person.
beside its name, checked there (`check-book`'s checks, on the documents the preflight
built, the printer closed first), and moved into place only once they pass, so a failed
run never leaves a partial book or one that fails its check. A run is whole: a failure in
any PDF writes none, and the step is run again.
- **Exit 1:** a fault from the preflight or FR-011, each printed as `check-book` prints it.
The report names each one by stable identifier or file name, never a person, and gives
each FR-011 check with its count of faults.
- **Exit 2:** bad arguments; a `--report` that exists already (left untouched, and no
report written), whose folder cannot be made, or that is inside `--out`; an `--out` that
is not absent or empty, as for `figures` (an old book is never replaced in place), that
Expand All @@ -118,12 +121,16 @@ the figures already drawn by `figures`.
128 and the signal's number. It exits rather than raising the signal again, as the
exit handlers that end the browser and remove its folders run only on an exit. A
signal while the browser is starting is acted on once it has started, and a second
signal then stops the run at once.
signal then stops the run at once. Once the book is checked and moved into place, a
signal stops nothing that is not done: the book is left in place, the report says it
was written (outcome `written`) and names the signal, and the exit is 0.
- **A private temporary folder:** the run makes one in TMPDIR at its start and points
everything it starts at it (the printer's pages, the browser launcher's folders and the
browser itself, by TMPDIR), and removes it, whole, as the process exits, after the
launcher has ended the browser; so a signal at any moment leaves nothing in TMPDIR. The
browser launcher's own signal handling is off, as in `serve`.
launcher has ended the browser; so SIGINT, SIGTERM or SIGHUP at any moment leaves nothing
in TMPDIR (SIGKILL, or the memory cap's kill, leaves it). One is live in a process at a
time, as TMPDIR is the process's: a second is refused. The browser launcher's own signal
handling is off, as in `serve`.

## `pdf-export preflight`

Expand Down Expand Up @@ -153,12 +160,15 @@ as in `--files` (`diagram/R-HSA-….json`), a figure's as in `--figures` (`R-HSA

FR-011's check, alone. Also run by `book`.

| Flag | Meaning |
| ---------------------- | ---------------------------------------------------------------------------------------- |
| `--graph`, `--species` | the graph the book was made from, for the list of top-level pathways and events expected |
| `--files` | the release's folder, for which events have a figure's source (FR-011) |
| Flag | Meaning |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--graph`, `--database`, `--species` | as for `book`: the graph the book was made from, for the list of top-level pathways and events expected |
| `--files` | the release's folder: its EHLD summary, for the Figure rules, as `book` reads it, and which events have a figure's source (FR-011); required |

- **Exit 0:** every check passed.
- **Exit 2:** bad arguments (one folder, `--files`, and a graph are needed); a folder that is
not one; no EHLD summary in `--files`; the graph cannot be reached at the start; or any
other error (a PDF that cannot be read, a graph that fails mid-run), on stderr.
- **Exit 1:** at least one fault, one line each:
- `fault missing-pathway <stId>`: a top-level pathway with no PDF;
- `fault extra-file "<file name>"`: a PDF in the folder that is no top-level pathway's;
Expand All @@ -168,8 +178,27 @@ FR-011's check, alone. Also run by `book`.
`no-stable-id`, `missing-figure` and `broken-link`.

A file is matched to its top-level pathway by name: the names expected are made from
the graph as `book` makes them. The PDFs are untagged, so sections are found by the
outline and the text at each entry's destination (research R8).
the graph as `book` makes them, and any other file or folder in the folder is an
`extra-file`. The PDFs are untagged, so they are read with pdf.js for their outline, links
and text (research R8), each event's printed texts after FR-017's substitutions:
- a **section** is found at its heading's link to the event's page on the website (the
first link there; a reaction's figure links there too, below it), where an outline or
contents entry with its name lands too, or else where the first such entry lands, and
runs to the next section found;
- `not-in-contents`: no contents entry (a link before the first section, its lines read
together) lands on the section and reads its name; `not-in-outline`: no outline entry,
at any depth, does both; an event whose section is not found at all is all three of
these and `no-name`;
- `no-name`: the section's heading (its leading text set larger than the body's 10.5 pt)
does not read its name; `no-stable-id`: its text holds no `Stable identifier` followed
by its stable identifier;
- `missing-figure`: a pathway's or reaction's section with a figure by the Figure rules,
whose source is in `--files` (its diagram's two files, its EHLD; a reaction's is the
graph), has no link to that figure's interactive form below its heading. The figure is
known by its link: a drawing lost with its link kept is not seen;
- `broken-link`: a link that lands on no page of its PDF, or is still a placeholder or
probe address (T026), named by the section it is in, or by the PDF's pathway for one in
its front parts, one line a section.

## `pdf-export compare <reference> <new>`

Expand Down Expand Up @@ -201,4 +230,6 @@ The single-event service (contracts/service.md).
SIGHUP once it serves closes it and exits 0; one before it serves, or another while it
closes, exits at once with 128 and the signal's number. Like `book`, it makes a private
temporary folder at its start for the printer and the browsers it starts, removed as
the process exits, so it leaves nothing in TMPDIR however it is stopped.
the process exits, so it leaves nothing in TMPDIR when it is stopped by SIGINT, SIGTERM
or SIGHUP. A process killed outright (SIGKILL, the memory cap's kill) or by a signal it
does not handle leaves the folder, as no exit handler runs.
5 changes: 4 additions & 1 deletion specs/001-pathway-pdfs/data-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ cause (`unanswered`, `failed`, `refused`, `invalid` or `label`, contracts/figure
time where they overlap (T029).
- The join's settings: `--joins`, `--parallel` and whether object streams are on
(research R4).
- Each FR-011 check, and its result (none until `check-book`, T030).
- Each FR-011 check (`check-book`, T030), with its count of faults, none a pass; none
when the run stopped before the check. Its faults are among the book's faults.
- The signal that stopped the run, if one did; once the book is in place, the outcome is
still the book written.
- The book's faults, each as `preflight` prints it, and the error that stopped it, if any.
- No names (FR-013).
12 changes: 11 additions & 1 deletion specs/001-pathway-pdfs/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ passes.
- **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/<pid>/task/<pid>/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 `.<name>-XXXXXX` beside `--out`, which a later run ignores and does not remove.

- [ ] T030 [US1] `check-book`, `src/check/book.ts` (FR-011, contracts/cli.md).
- [x] T030 [US1] `check-book`, `src/check/book.ts` (FR-011, contracts/cli.md).
- **Flags:** `--graph`, `--species` and `--files`.
- **Output:** one line per fault, in contracts/cli.md's three forms: `fault missing-pathway <stId>`, `fault extra-file "<file name>"`, and `fault <kind> "<file name>" <stId>` for the rest.
- **Method:** it reads the graph, and the book's outline and text, since the book is untagged.
Expand All @@ -517,6 +517,16 @@ passes.

`book` runs it on the folder, and exits 0 only when it passes. Tests: a fixture book with each fault planted one at a time fails with that fault's line (SC-007).

- **Done (#160):** `checkBook(folder, docs, files)` (`src/check/book.ts`) checks a book's folder against the documents it was made from: `book` gives the preflight's, `pdf-export check-book <folder>` (`checkBookCommand`, wired into `src/cli.ts`) builds them from the graph as `book` does, with `--graph`, `--database` (added beside the contract's two, as `preflight` has it), `--species` and `--files` (required: its EHLD summary decides the Figure rules, its files which figures' sources exist). Exit 0 with no fault, 1 with any (`fault <fault>`, one line each, in the contract's three forms), 2 on bad arguments, a folder that is not one, no EHLD summary, a graph that cannot be reached at the start (its own driver retrying briefly, as `preflight`'s) or any other error. **What it reads:** each PDF with pdf.js, page by page: its text in the text area (the stamps in the margins left out), its links (an address, or where an internal one lands: a page of the PDF and a height, or nowhere) and its outline at every depth; each event's expected texts are as printed, after FR-017's substitutions (`printedDocument`). **The faults:** `missing-pathway <stId>` for a pathway whose file (named from the graph as `book` names it) is absent; `extra-file "<name>"` for any other file or folder in the folder; then, PDF by PDF in the book's order and event by event in document order, `not-in-contents`, `not-in-outline`, `no-name`, `no-stable-id` and `missing-figure`, then `broken-link`. **How a section is found** (the book is untagged, research R4, R8): at its heading's link to the event's page on the website, the first link there in reading order, where an outline or contents entry with its name lands too; else where the first such entry lands (a heading that lost its link, whose first link is then a reaction's figure's); else at that link; it runs to the next section found. An entry is the event's when it lands within 3 pt of the section's start (a destination is the top of the heading's line, its link the top of its text, 0.5 to 1.5 pt lower on the fixture) and reads its name: the contents list's entries are the links before the first section, an entry's lines (one link a line) read together. The heading is the section's leading text set above 11.25 pt (the body is 10.5 pt, the smallest heading 12); the stable identifier a piece after `Stable identifier`, or in one piece with it; the figure a link to the figure's interactive form (`Links.figure`, matched by its path, as `check-book` has no `--site`) below the heading's last line, so a reaction's heading link to the same page is not taken for it, checked only where the source exists (`neededFiles` all in `--files`; a reaction's is the graph). A link is broken when it lands on no page of its PDF or is still a placeholder or probe address (T026), one line a section, named by the section it is in, or the PDF's pathway in the front parts. An event whose section is found nowhere is `not-in-contents`, `not-in-outline` and `no-name`. **In `book`:** the printer is closed once the PDFs are written (its browser not held through the check), the check runs on the folder beside `--out`, its faults are exit 1 (printed, in the report's faults, the folder removed, no book), and only then is the folder renamed into place. The run report's `checks` is every check with its count of faults (`null` if the run stopped before it), its `check-book` stage timed, and the PDFs, figures, characters and stages are noted before the check, so a report written at any later moment holds them.
- **Tests:** `test/check/book.test.ts` (10): the fixture's book printed once by `book` (exit 0, its TMPDIR left empty), and each fault planted, one at a time, in a copy of its folder or of `beta pathway.pdf` with pdf-lib, never in the shared fixture; each fails with exactly its line. The book as written passes, and passes saved again unchanged; Gamma's PDF removed (`missing-pathway R-HSA-90000300`); a PDF copied as `Delta pathway.pdf` (`extra-file`); Reaction eight's (R-HSA-90000132, at one place in beta) contents link removed, and its contents text erased with its link kept (`not-in-contents`); its outline entry taken out, and retitled `Reaction nine` (`not-in-outline`); its heading's text erased (`no-name`); its stable identifier's text erased (`no-stable-id`); its figure's link removed, and beta sub with diagram's (R-HSA-90000130) diagram's link, but not with that diagram's file taken from a copy of `--files` (`missing-figure`); its first internal link landing on the catalog, not a page, and turned back into a placeholder (`broken-link`). Text is erased by taking the `BT … ET` runs that read it, through their fonts' ToUnicode maps, out of the page's content (Chromium writes one a run, its glyphs as two-byte codes). The command: exit 0 and nothing printed on the book; exit 1 with the two lines of two plants; exit 2 on no folder, two, no `--files`, an unknown flag, a flag with no value, no graph, a file for the folder, no EHLD summary and an address that cannot be read. `test/book/book.test.ts`: the exit-0 test now holds every check passed and timed, and 3 tests are added: a printer that drops Reaction eight's name from its heading (as a layout might) is exit 1 with `fault no-name "beta pathway.pdf" R-HSA-90000132` alone, nothing left, the report's `checks` saying so; and two from #159's review, below. 418 tests before, 433 after (with `test/print/print.test.ts`'s and `test/print/temporary.test.ts`'s, below). Each of these mutants made one fail: each check's faults left out, one at a time (its plant's test; `missing-pathway` and `not-in-outline` also the command's); the contents entry's text not read, and the outline entry's title not read (the erased-text and retitled plants); the figure's link taken above the heading too (the reaction's plant, its heading's link counted); every figure's source taken to exist (the no-source case); placeholders not broken, and links landing nowhere not broken (each its plant); a broken link named by the PDF's pathway (the broken-link test); the heading taken as all the section's text (every test: the book fails its own check); the stable identifier's label taken without its value (the no-stable-id test); a section always at its first link to its page (the book's dropped-name test: its first link is then its figure's, and it is five faults where it is one); in `book`, the check not run (the exit-0 and dropped-name tests), and its faults ignored (the dropped-name test).
- **From #159's review:** five lows.
- **Printer leaks:** the book's tests read TMPDIR after the run's private folder, which holds the printer's, is removed, so a printer leaving its own `pdf-export-*` passed them. `test/print/print.test.ts` adds a test, with or without the graph: a printer started with TMPDIR a folder of its own makes its folder there, prints, closes, and leaves the folder empty; with `close` not removing its folder, it fails.
- **One live private folder a process:** `privateTemporary` throws while one is live (TMPDIR is the process's; a second left it naming a removed folder, and the two exit handlers could move each other last for ever), and `remove` restores TMPDIR and lets its handlers go before removing the folder, so a removal that fails leaves the process as it was. `test/print/temporary.test.ts`: a second refused while the first is live, changing nothing, and allowed once it is removed; without the check, the two exit handlers moved each other last for 32 s, until a `RangeError: Map maximum size exceeded` failed the file.
- **Cleanup on an exception:** everything in `bookCommand` after the folder is made is in a `try`, whose `finally` lets the signal handlers go and removes the folder, saying on stderr if that fails. `end` no longer removes it, so the report is written first. A test opens the graph with a `close` that rejects and an `err` that throws on being told so, which escapes between the start and `end`: the run rejects, and TMPDIR is restored and left empty, and no SIGTERM handler is left. With the removal back in `end` alone, as before, it fails.
- **The serve contract:** it now says `serve` leaves nothing in TMPDIR when stopped by SIGINT, SIGTERM or SIGHUP, and that SIGKILL, the memory cap's kill or an unhandled signal leave the folder; `book`'s bullet likewise.
- **A signal after the final rename (T029's L3, changed):** decided, once the book is checked and in place a signal stops nothing that is not done: the folder variable is cleared after the rename and the run is marked placed, and a signal then writes the report with the outcome `written`, the signal in a new `signal` field (`error` null), and exits 0 (2 if the report cannot be written); before, it exits 128 and the signal's number with `outcome: 'error'` as it did, `signal` set too. contracts/cli.md and data-model.md say so. The test runs `book` in-process with an `exit` it can catch (`BookIo.exit`, `process.exit` by default) and sends SIGTERM as the run says the book is written (after the rename): exit 0, the book in place, the report written with the PDFs and every check passed, and the handlers gone. Each of these mutants made it fail: the signal handled as before the rename, and the run never marked placed.
- **Known gaps:** the rules are measured on the fixture alone, whose names are short and whose figures small: T031 runs the check on release 98's book, and its time against R7's 9 minutes. A figure is known by its link: a drawing lost with its link kept is not seen. A heading that lost its link and every entry naming it is found nowhere, and is then three faults. A link landing on a page but not on its target is not a fault (R8: every link landing on a page). Between `bookCommand` returning and the process ending there are no handlers, so a signal then is the default action, exit 128 and its number, the book and its report already in place.

- [ ] T031 [US1] The book on a private copy of release 98's graph.
- Run `figures` first and time it for SC-010; then time each of `book`'s stages against research R7's budget, check memory, and run `check-book`. Record the results in research R7.
- T029's memory measurement, left here: the join's memory on the real book, object streams on and off, beside printing; raise `--joins` to 2 only if two real joins fit, choose object streams from it (off until then), and do T012 first if one real join does not fit.
Expand Down
Loading
Loading