featkpr
Private demo

BookStack: what featkpr missed, 605 of 2,372, step by step

featkpr onboarded BookStack again from a fresh start with no help and checked each step against an answer key. For every step but one the key is independent of featkpr; for routes it is the same list the reader uses, so that row counts what was dropped. Of 2,372 things in the key, featkpr gathered 1,437 and missed 605 at the step that should have found them; the rest were lost because an earlier step missed them. The figure below counts them by step and by reason.

the missed-items check: it reads every step

Step, checked againstgathered · missed at this step · lost at an earlier stepCommonest reason, with one real case
Routes readthe route list Laravel prints 343 of 359 · 16 missed not built yetBookStack's console commands, such as bookstack:assign-sort-rule: no part of featkpr reads commands a person runs yet.
the audit's own wordsbookstack:assign-sort-rule · not built: no adapter reads console commands: an entry point a person runs is never a candidate
Permission checks foundchecks in each handler and route middleware 193 of 194 · 1 missed a reader missed itPUT /api/users/{id} checks its permission with a name built while it runs, so there is no name in the code to read.
the audit's own wordsPUT /api/users/{id} · detector gap: the handler calls userCan with a computed name (no literal to read); the pass stored no presence
Routes a feature citesevery route, against what the naming said 356 of 587 · 231 missed a reader missed itDELETE /ajax/page/{id}: no named feature claims this route, and nothing on its page links it to one.
the audit's own wordsDELETE /ajax/page/{id} · detector gap: no reply cites the route, and contains joins it to nothing a feature cites (no view or string of its page)
Pages reachedevery GET route 96 of 198 · 102 missed a reader missed itGET /ajax/tags/suggest/names: the crawl reached it, but it is not a page, and featkpr kept no record that it was reached.
the audit's own wordsGET /ajax/tags/suggest/names · detector gap: the crawl reached it (other: not an HTML page) and no stored fact says so; only the crawl report holds it
Screens capturedGET routes that draw a page 77 of 137 · 5 missed · 55 lost earlier a limit we setGET /api-tokens/{userId}/create: the crawl skips API-token pages on purpose.
the audit's own wordsGET /api-tokens/{userId}/create · cap: the policy's no_shots list
Forms foundthe templates' forms 62 of 93 · 19 missed · 12 lost earlier a reader missed itThe image manager's delete form: a script sets where it sends, so the template names no route to join it to.
the audit's own wordsDELETE @resources/views/pages/parts/image-manager-form.blade.php:84 · detector gap: its action is not a URL the template spells (set by script, or a variable): no route to join
Forms sentthe forms that change something 4 of 87 · 52 missed · 31 lost earlier a limit we setDELETE /api-tokens/{userId}/{tokenId}: the crawl sends only forms that create something, and this one deletes.
the audit's own wordsDELETE /api-tokens/{userId}/{tokenId} · cap: not on the policy's create-only allow-list (submit fills only allow-listed forms)
Flows foundentry to target, per role 141 of 191 · 24 missed · 26 lost earlier a limit we setFrom the home page to a chapter: every way there runs through records the crawl made itself, and those flows are left out on purpose.
the audit's own wordsGET / → GET /books/{bookSlug}/chapter/{chapterSlug} · cap: every path passes through what the crawl made itself (a page carrying a submission's marker, or the record a writing GET made): held by 'flows clean'
Outcomes per featurewho gets what, per permission 86 of 404 · 112 missed · 206 lost earlier a limit we setGET /: no named feature starts at the home page, so nobody's outcomes on it were drafted.
the audit's own wordsGET / · cap: one tree per named feature, from its root: the naming cites the route (or what its page shows) and roots no feature's tree here, nor at an atom its gate reads
Tests writtenone per stored outcome 76 of 86 · 10 missed not built yetDELETE /settings/users/{id}/mfa, the refused case: this route checks no permission, and every test template expects one.
the audit's own wordsDELETE /settings/users/{id}/mfa · refused · not built: an ungated leaf on DELETE /settings/users/{id}/mfa: every template declares gated shapes only
Seeded records seenwhat the seed creates 3 of 9 · 6 missed a limit we setThe seeded user “M6 Content Only”: the crawl found its page, and a cap on pages of one pattern left it out.
the audit's own wordsthe seeded user 'M6 Content Only' (M6 Content-only reader) · cap: the crawl found /user/m6-content-only and the per-pattern cap left it out
Effects seenmail, downloads, off-host links 0 of 27 · 27 missed a reader missed itGET /api/docs/download: the crawl downloaded the file, and kept its type, size and hash only in its own report.
the audit's own words/api/docs/download · detector gap: the crawl downloaded it; its type, size and hash stay in the crawl report
BookStack · the missed-items check of 26 Sep 2026, exported · commit 0f5164ec · a replay of the admin crawl · of 2,372 things: 1,437 gathered, 605 missed at their own step, 330 lost at an earlier step · of the 605, 592 are featkpr’s own gaps; the audit puts 13 down to BookStack’s side (pages only a signed-out visitor sees, forms nothing links to)

A miss costs the steps after it

Pages reached102 missed here
55 lostScreens captured77 of 137
12 lostForms found62 of 93
Forms found19 missed here
31 lostForms sent4 of 87
26 lostFlows found141 of 191
Routes a feature cites231 missed here
206 lostOutcomes per feature86 of 404
each thing is counted missed once, at the step that lost it, and as lost earlier at every later step that needed it

Why, across all steps

  1. 295a reader missed it the step ran, and its reader did not see this one
  2. 199a limit we set left out by a cap or an allow-list, on purpose for now
  3. 67not built yet no part of featkpr reads this kind of thing yet
  4. 28needed a record first the page needs an id no crawled page linked to
  5. 10needed another user only a signed-out visitor sees it, and no signed-out crawl ran
  6. 3nothing links to it no page renders it by a name the source spells
  7. 3kept out on purpose an off-host address the crawl never follows
605 missed things by reason · “a limit we set” is a cap or an allow-list chosen on purpose for now
Every step against every reason
a reader missed ita limit we setnot built yetneeded a record firstneeded another usernothing links to itkept out on purposelost earlier Routes read 16 Permission checks found 1 Routes a feature cites 231 Pages reached 3833283 Screens captured 555 Forms found 97312 Forms sent 5231 Flows found 2426 Outcomes per feature 112206 Tests written 46 Seeded records seen 6 Effects seen 12123 all steps29519967281033

BookStack: its six steps and the report

See this change live, on a call #

Tim opens BookStack in featkpr with you: the map, the flows, any test and both of its runs.

Ask for a private demo

↑ ↓ to move, Enter to open, Esc to close