E2E: isolated test cases in their own CI job; mem-check measures only (#38) #40

Merged
claude-bot merged 13 commits from phase1/e2e into main 2026-10-22 18:47:29 +00:00
Collaborator

What

The user flows mem-check used to assert are now 8 isolated cases in tools/e2e/ (own HOME/XDG, KJV-only Bible folder, own Xvfb, fixed window; taps by the geometry the app logs). mem-check measures only start time and PSS (D10). CI gets an e2e job between app and click; it fails on any skip, and reruns the four timer cases in the slow profile. Locally: cargo make e2e-docker, E2E_CASES="picker-back aa-sheet" for some.

Closes #38.

Blast radius

Tier: trunk
Trunk paths touched: .forgejo/workflows/ci.yml, Makefile.toml, tools/ci/, tools/e2e/ (new, added to the trunk list), tools/mem-check/, qml/pages/ReadingPane.qml, CLAUDE.md
Testing tier: maximum (CI config) (also: standard)
Gate / rollback: revert this merge. Nothing ships to users: the QML changes only add console.log geometry lines (utsb: grid, utsb: sheet) and a Theme.where() helper.

Old check → case

mem-check (before) now
kill -9 restore, core and on screen restore
inactive save inactive-save
no jump while chapters slide, fling reaches chapters scroll-chapters (reach guard also stays in mem-check)
jump, then Back to the exact place picker-back
Back after kill back-after-kill
typed reference hidden, on, jn 3,16 jumps typed-reference
Aa night colour, text taller, top verse kept aa-sheet
Aa settings back before the text after kill -9 aa-sheet-kill
peak PSS with picker and Aa sheet; start-time and PSS budgets stay in mem-check

Proof

  • Fails without the change: each case FAILs (exit 105) against a defect it guards, in a scratch copy in the CI image: restore line dropped, no flush on inactive, 2000 px jump on rows inserted (25–28-verse jumps), Back loads fraction 0, history never pushed, typed field always visible, top-verse keep dropped, setting never read back.
  • Targeted check (CI job catches what it targets): a SWORD folder without KJV → e2e: no case passed, exit 1; with E2E_STRICT=1 (CI's default) skips count as failures.
  • Isolation: reversed order 8/8, shuffled 8/8, picker-back twice 2/2.
  • On 91873a8, local cargo make e2e-docker, KJV-only folder: e2e: 8 passed, 0 failed, 0 skipped, then e2e: 4 passed, 0 failed, 0 skipped, slow profile.
  • cargo make app-docker (mem-check normal and SLOW=1) on both folders and cargo make: exit 0.
  • CI on 91873a8: rust 3m22, audit 11s, app 1m54, e2e 3m04, click 1m04, all success. The app job went from 3m48 on main to about 1m55.
  • scroll-chapters on a quiet runner (run 104): steps of at most 7 verses down and up. Owner decision: the limit is 15 verses a step (a loaded runner reported 11; a real jump is a chapter, 22+ verses in Gen 1–11).
  • Start budget, normal profile, 2 s → 3 s: CI measured 1.2–2.4 s for text on screen, and the old environment 2.2 s on the same binary; docs/09 says why.

Review

Reviewer: fresh-context code-review at high (238), re-review at medium (239), delta review at medium (240): 6 findings (1+1 medium, 4 low), 6 fixed (84d6614, 91873a8), 0 declined, 0 deferred, 0 fixed after the delta review, 0 left open.
Review-Confidence: 100/100, a full high review plus two re-reviews cover every trunk file and every fix, CI is green on 91873a8, and each case is shown to fail against the defect it guards.

Confidence by part

  • tools/e2e/lib.sh waits (e2e_settle, e2e_scroll): medium. Proven by defects and orders, but timing-based under software GL; flaked once on a CPU-starved runner before the box was power-cycled.
  • CI wiring (artifact, strict mode, slow rerun): high, exercised green on head.
  • QML geometry lines: high, log-only.
  • Unexplained earlier failures (#34, run 101 app, a0b80e8 e2e) predate the log artifacts; the artifacts now catch the next one.

🤖 Generated with Claude Code

## What The user flows mem-check used to assert are now 8 isolated cases in `tools/e2e/` (own HOME/XDG, KJV-only Bible folder, own Xvfb, fixed window; taps by the geometry the app logs). mem-check measures only start time and PSS (D10). CI gets an `e2e` job between `app` and `click`; it fails on any skip, and reruns the four timer cases in the slow profile. Locally: `cargo make e2e-docker`, `E2E_CASES="picker-back aa-sheet"` for some. Closes #38. ## Blast radius **Tier:** trunk **Trunk paths touched:** `.forgejo/workflows/ci.yml`, `Makefile.toml`, `tools/ci/`, `tools/e2e/` (new, added to the trunk list), `tools/mem-check/`, `qml/pages/ReadingPane.qml`, `CLAUDE.md` **Testing tier:** maximum (CI config) (also: standard) **Gate / rollback:** revert this merge. Nothing ships to users: the QML changes only add `console.log` geometry lines (`utsb: grid`, `utsb: sheet`) and a `Theme.where()` helper. ## Old check → case | mem-check (before) | now | |---|---| | kill -9 restore, core and on screen | `restore` | | inactive save | `inactive-save` | | no jump while chapters slide, fling reaches chapters | `scroll-chapters` (reach guard also stays in mem-check) | | jump, then Back to the exact place | `picker-back` | | Back after kill | `back-after-kill` | | typed reference hidden, on, `jn 3,16` jumps | `typed-reference` | | Aa night colour, text taller, top verse kept | `aa-sheet` | | Aa settings back before the text after kill -9 | `aa-sheet-kill` | | peak PSS with picker and Aa sheet; start-time and PSS budgets | stay in mem-check | ## Proof - Fails without the change: each case FAILs (exit 105) against a defect it guards, in a scratch copy in the CI image: restore line dropped, no flush on inactive, 2000 px jump on rows inserted (25–28-verse jumps), Back loads fraction 0, history never pushed, typed field always visible, top-verse keep dropped, setting never read back. - Targeted check (CI job catches what it targets): a SWORD folder without KJV → `e2e: no case passed`, exit 1; with `E2E_STRICT=1` (CI's default) skips count as failures. - Isolation: reversed order 8/8, shuffled 8/8, `picker-back` twice 2/2. - On 91873a8, local `cargo make e2e-docker`, KJV-only folder: `e2e: 8 passed, 0 failed, 0 skipped`, then `e2e: 4 passed, 0 failed, 0 skipped, slow profile`. - `cargo make app-docker` (mem-check normal and SLOW=1) on both folders and `cargo make`: exit 0. - CI on 91873a8: rust 3m22, audit 11s, app 1m54, e2e 3m04, click 1m04, all success. The app job went from 3m48 on main to about 1m55. - scroll-chapters on a quiet runner (run 104): steps of at most 7 verses down and up. **Owner decision:** the limit is 15 verses a step (a loaded runner reported 11; a real jump is a chapter, 22+ verses in Gen 1–11). - Start budget, normal profile, 2 s → 3 s: CI measured 1.2–2.4 s for text on screen, and the old environment 2.2 s on the same binary; docs/09 says why. ## Review **Reviewer:** fresh-context `code-review` at high (238), re-review at medium (239), delta review at medium (240): 6 findings (1+1 medium, 4 low), 6 fixed (84d6614, 91873a8), 0 declined, 0 deferred, 0 fixed after the delta review, 0 left open. **Review-Confidence:** 100/100, a full high review plus two re-reviews cover every trunk file and every fix, CI is green on 91873a8, and each case is shown to fail against the defect it guards. ## Confidence by part - `tools/e2e/lib.sh` waits (`e2e_settle`, `e2e_scroll`): medium. Proven by defects and orders, but timing-based under software GL; flaked once on a CPU-starved runner before the box was power-cycled. - CI wiring (artifact, strict mode, slow rerun): high, exercised green on head. - QML geometry lines: high, log-only. - Unexplained earlier failures (#34, run 101 app, a0b80e8 e2e) predate the log artifacts; the artifacts now catch the next one. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
E2E: isolated test cases in their own CI job; mem-check measures only (#38)
Some checks failed
CI / rust (pull_request) Successful in 14m1s
CI / audit (pull_request) Successful in 31s
CI / app (pull_request) Failing after 5m23s
CI / e2e (pull_request) Has been skipped
CI / click (pull_request) Has been skipped
a0a575f620
tools/e2e/ holds a shared lib.sh, a runner and one case per flow that
mem-check used to assert. Each case gets its own temp HOME, Bible folder
(KJV only where possible), Xvfb and data folder, taps by the geometry the
app reports, and asserts on the app's trace lines. mem-check keeps only
start time and PSS. CI gets an e2e job after app (the binary is passed as
an artifact); click needs e2e. cargo make e2e-docker runs it locally
(E2E_CASES picks cases).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: temporary app.log artifact to see the app job failure (#38)
Some checks failed
CI / rust (pull_request) Successful in 13m3s
CI / audit (pull_request) Successful in 28s
CI / app (pull_request) Failing after 4m55s
CI / e2e (pull_request) Has been skipped
CI / click (pull_request) Has been skipped
a312fe6cb3
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: temporary start-time probe (#38)
Some checks failed
CI / rust (pull_request) Successful in 12m27s
CI / audit (pull_request) Successful in 27s
CI / app (pull_request) Failing after 4m30s
CI / e2e (pull_request) Has been skipped
CI / click (pull_request) Has been skipped
42a4c1ed38
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: temporary start-time probe, old env vs new (#38)
Some checks failed
CI / rust (pull_request) Successful in 10m35s
CI / audit (pull_request) Successful in 33s
CI / app (pull_request) Failing after 5m52s
CI / e2e (pull_request) Has been skipped
CI / click (pull_request) Has been skipped
9383a81b3c
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
mem-check: normal-profile start budget 3 s (CI measures 1.2 to 2.4 s); drop the CI probes (#38)
Some checks failed
CI / rust (pull_request) Successful in 11m29s
CI / audit (pull_request) Successful in 28s
CI / app (pull_request) Successful in 5m17s
CI / e2e (pull_request) Failing after 4m8s
CI / click (pull_request) Has been skipped
a0b80e811a
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: e2e job keeps its logs as an artifact on failure (#38)
All checks were successful
CI / rust (pull_request) Successful in 13m43s
CI / audit (pull_request) Successful in 38s
CI / app (pull_request) Successful in 6m6s
CI / e2e (pull_request) Successful in 2m55s
CI / click (pull_request) Successful in 4m11s
186e5ccba5
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: rerun to see whether the e2e job flakes (#38)
Some checks failed
CI / rust (pull_request) Successful in 13m7s
CI / audit (pull_request) Successful in 35s
CI / app (pull_request) Failing after 4m57s
CI / e2e (pull_request) Has been skipped
CI / click (pull_request) Has been skipped
27e0f0d447
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: app job keeps its log as an artifact on failure (#38)
Some checks failed
CI / rust (pull_request) Successful in 12m45s
CI / audit (pull_request) Successful in 32s
CI / app (pull_request) Successful in 5m31s
CI / e2e (pull_request) Failing after 2m53s
CI / click (pull_request) Has been skipped
0926aba0dd
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
e2e: a count never meets a missing log; scroll-chapters allows 15 verses a step (CI saw 11) (#38)
Some checks failed
CI / rust (pull_request) Successful in 4m5s
CI / audit (pull_request) Successful in 10s
CI / app (pull_request) Successful in 1m58s
CI / e2e (pull_request) Has been cancelled
CI / click (pull_request) Has been cancelled
a98bcbf0ca
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
e2e: scroll-chapters back to 10 verses a step; the 15 rested on a cancelled run (#38)
All checks were successful
CI / rust (pull_request) Successful in 3m49s
CI / audit (pull_request) Successful in 10s
CI / app (pull_request) Successful in 1m59s
CI / e2e (pull_request) Successful in 2m0s
CI / click (pull_request) Successful in 1m9s
7b48d19325
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
claude-review requested changes 2026-10-22 17:46:45 +00:00
Dismissed
claude-review left a comment

Level: HIGH (single pass). Commit: 7b48d19325. Range: origin/main...HEAD (22 files, +826/-383). Blast radius: trunk; testing tier: maximum.

Files reviewed: .forgejo/workflows/ci.yml, Makefile.toml, tools/ci/e2e.sh, tools/ci/app.sh (context), tools/e2e/lib.sh, tools/e2e/run.sh, tools/e2e/cases/*.sh (8), tools/mem-check/run.sh (and origin/main's copy, compared assertion by assertion), tools/mem-check/budget-start-ms, qml/pages/PickerPage.qml, QuickSettings.qml, ReadingPane.qml, qml/theme/Theme.qml, CLAUDE.md, docs/09-quality-gates.md, docs/03-architecture.md.

Assertion parity: every assertion main's mem-check had is kept by a case or by mem-check (PSS and start budgets, chapters reached, no-jump, restore, inactive save, picker and Back, Back after kill, typed reference, Aa sheet and its kill). Not verified here: the targeted maximum-tier check (each case fails against the defect it guards, in the CI image). I could not run the CI image from this review.

Findings outside the diff lines:

  • medium · tools/e2e/run.sh:69 / tools/ci/e2e.sh · If KJV is not found in the SWORD folder (fetch.sh layout change, a partial cache restore, a conf whose [Name] line doesn't match), every case exits 77 and the runner prints "0 passed, 0 failed, 8 skipped" and exits 0. The e2e job goes green having run nothing, and click (needs: e2e) proceeds. On main this would have failed mem-check. Fix: in CI (e.g. E2E_REQUIRE=1 from e2e.sh) treat SKIP as failure, or fail when pass == 0.
  • low · tools/e2e/lib.sh:153 · e2e_quiet gives up after one 1.6 s gap with no new 'utsb: saved ' line, but the core's save comes about 1 s after the last top report and can arrive later under llvmpipe load. If the save is late the wait passes on the stale line, so e2e_scroll_into_verse / picker-back / aa-sheet read a stale e2e_saved. A flake, not a false pass. Fix: wait for a save newer than the scroll first, then for quiet.
  • low · tools/e2e/lib.sh:177 · e2e_scroll accepts any new 'utsb: top ' line within 1.5 s of the first wheel. A late initial report after launch (restore or layout) can satisfy it though the wheel click was lost. restore and inactive-save then check a position that was never scrolled, so they can pass vacuously.
  • low · tools/mem-check/run.sh · The behaviour cases no longer run in the slow profile (2 CPUs, one shared with a busy loop). main exercised restore, inactive-save and Back under SLOW=1; now only normal-profile e2e runs them. Say so in docs/09 or run a subset with E2E_LAUNCH.
  • low · tools/e2e/run.sh · timeout -k 5 sends KILL after the case's TERM trap; when a case hangs in a foreground child, the EXIT trap may not run, leaking the temp sandbox. The app and Xvfb die with the process group, so there is no outside-sandbox damage.

No cleanup path deletes or kills outside its own mktemp dir, pid or Xvfb. Isolation (HOME, XDG, Bible folder, display via -displayfd, per-launch logs) is sound.

Level: HIGH (single pass). Commit: 7b48d19325ffba43690e2f4648a6156b4f093392. Range: origin/main...HEAD (22 files, +826/-383). Blast radius: trunk; testing tier: maximum. Files reviewed: .forgejo/workflows/ci.yml, Makefile.toml, tools/ci/e2e.sh, tools/ci/app.sh (context), tools/e2e/lib.sh, tools/e2e/run.sh, tools/e2e/cases/*.sh (8), tools/mem-check/run.sh (and origin/main's copy, compared assertion by assertion), tools/mem-check/budget-start-ms, qml/pages/PickerPage.qml, QuickSettings.qml, ReadingPane.qml, qml/theme/Theme.qml, CLAUDE.md, docs/09-quality-gates.md, docs/03-architecture.md. Assertion parity: every assertion main's mem-check had is kept by a case or by mem-check (PSS and start budgets, chapters reached, no-jump, restore, inactive save, picker and Back, Back after kill, typed reference, Aa sheet and its kill). Not verified here: the targeted maximum-tier check (each case fails against the defect it guards, in the CI image). I could not run the CI image from this review. Findings outside the diff lines: - medium · tools/e2e/run.sh:69 / tools/ci/e2e.sh · If KJV is not found in the SWORD folder (fetch.sh layout change, a partial cache restore, a conf whose [Name] line doesn't match), every case exits 77 and the runner prints "0 passed, 0 failed, 8 skipped" and exits 0. The e2e job goes green having run nothing, and `click` (needs: e2e) proceeds. On main this would have failed mem-check. Fix: in CI (e.g. E2E_REQUIRE=1 from e2e.sh) treat SKIP as failure, or fail when pass == 0. - low · tools/e2e/lib.sh:153 · e2e_quiet gives up after one 1.6 s gap with no new 'utsb: saved ' line, but the core's save comes about 1 s after the last top report and can arrive later under llvmpipe load. If the save is late the wait passes on the stale line, so e2e_scroll_into_verse / picker-back / aa-sheet read a stale e2e_saved. A flake, not a false pass. Fix: wait for a save newer than the scroll first, then for quiet. - low · tools/e2e/lib.sh:177 · e2e_scroll accepts any new 'utsb: top ' line within 1.5 s of the first wheel. A late initial report after launch (restore or layout) can satisfy it though the wheel click was lost. restore and inactive-save then check a position that was never scrolled, so they can pass vacuously. - low · tools/mem-check/run.sh · The behaviour cases no longer run in the slow profile (2 CPUs, one shared with a busy loop). main exercised restore, inactive-save and Back under SLOW=1; now only normal-profile e2e runs them. Say so in docs/09 or run a subset with E2E_LAUNCH. - low · tools/e2e/run.sh · timeout -k 5 sends KILL after the case's TERM trap; when a case hangs in a foreground child, the EXIT trap may not run, leaking the temp sandbox. The app and Xvfb die with the process group, so there is no outside-sandbox damage. No cleanup path deletes or kills outside its own mktemp dir, pid or Xvfb. Isolation (HOME, XDG, Bible folder, display via -displayfd, per-launch logs) is sound.
@ -0,0 +68,4 @@
e2e_bible=$e2e_work/data/utstudybible.schaefera/sword
mkdir -p "$e2e_bible/mods.d"
for e2e_m in "$@"; do
e2e_module "$e2e_m" || { echo "$e2e_tag: SKIP: module $e2e_m is not in $E2E_SWORD"; exit 77; }
Collaborator

medium · SKIP exits 77 and the runner counts it as non-failing, so a CI run where KJV is not found is green with 0 passed. Make SKIP a failure in CI, or fail when nothing passed.

medium · SKIP exits 77 and the runner counts it as non-failing, so a CI run where KJV is not found is green with 0 passed. Make SKIP a failure in CI, or fail when nothing passed.
e2e: a skip fails in CI and a run with no pass fails; saves awaited, not guessed; timer cases also in the slow profile; sandboxes under the runner's temp (#38)
All checks were successful
CI / rust (pull_request) Successful in 3m54s
CI / audit (pull_request) Successful in 11s
CI / app (pull_request) Successful in 1m59s
CI / e2e (pull_request) Successful in 3m5s
CI / click (pull_request) Successful in 1m9s
84d66144bd
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Collaborator

Answering review 238 (reply to inline comment 1626 and the four lows). Fixed in 84d6614; no trunk path changed (tools/e2e, tools/ci, tools/mem-check, docs only; tools/ci/ and tools/e2e/ are in the trunk list of CLAUDE.md, so: yes, tools/e2e/ and tools/ci/ are trunk paths, no Rust/QML/C++ changed).

  • medium, SKIP green with nothing run: fixed in 84d6614. run.sh now exits 1 if no case passed, and with E2E_STRICT=1 (set by tools/ci/e2e.sh, so by CI) a skip counts as a failure. Proof: against a SWORD folder without KJV, run.sh gives "0 passed, 0 failed, 2 skipped / e2e: no case passed", exit 1 (default), and with E2E_STRICT=1 "(failed: restore(skipped) picker-back(skipped))", exit 1.
  • low, e2e_quiet one-gap on saves: fixed. New e2e_settle waits for the top-verse reports to go quiet, then for a saved line after the last top line (up to 15 s), then the saved-quiet gap, and starts over if a report came meanwhile. All cases and e2e_scroll_into_verse use it.
  • low, e2e_scroll passing on a late initial report: fixed. It first waits for the top reports to go quiet (the start's), then baselines.
  • low, slow profile no longer covers the behaviour cases: fixed. The profile moved into lib.sh (E2E_SLOW=1; mem-check uses it too) and tools/ci/e2e.sh runs restore, inactive-save, picker-back and back-after-kill again in it (logs in <case>-slow).
  • low, timeout -k leaking the sandbox: fixed. The runner points TMPDIR at the case's own out folder and removes it after the case, so a killed case leaves nothing outside.

Runs: cargo make e2e-docker with the full cache and with the KJV-only folder, each: 8 passed, 0 failed, 0 skipped, then slow profile 4 passed. cargo make app-docker both ways: exit 0, mem-check normal and slow peak PSS 140-146 MB (budget 165000 kB), 14 chapters. CI on the new head is running.

Answering review 238 (reply to inline comment 1626 and the four lows). Fixed in 84d6614; no trunk path changed (tools/e2e, tools/ci, tools/mem-check, docs only; tools/ci/ and tools/e2e/ are in the trunk list of CLAUDE.md, so: yes, `tools/e2e/` and `tools/ci/` are trunk paths, no Rust/QML/C++ changed). - medium, SKIP green with nothing run: fixed in 84d6614. `run.sh` now exits 1 if no case passed, and with `E2E_STRICT=1` (set by `tools/ci/e2e.sh`, so by CI) a skip counts as a failure. Proof: against a SWORD folder without KJV, `run.sh` gives "0 passed, 0 failed, 2 skipped / e2e: no case passed", exit 1 (default), and with E2E_STRICT=1 "(failed: restore(skipped) picker-back(skipped))", exit 1. - low, `e2e_quiet` one-gap on saves: fixed. New `e2e_settle` waits for the top-verse reports to go quiet, then for a `saved` line after the last `top` line (up to 15 s), then the saved-quiet gap, and starts over if a report came meanwhile. All cases and `e2e_scroll_into_verse` use it. - low, `e2e_scroll` passing on a late initial report: fixed. It first waits for the `top` reports to go quiet (the start's), then baselines. - low, slow profile no longer covers the behaviour cases: fixed. The profile moved into lib.sh (`E2E_SLOW=1`; mem-check uses it too) and `tools/ci/e2e.sh` runs restore, inactive-save, picker-back and back-after-kill again in it (logs in `<case>-slow`). - low, `timeout -k` leaking the sandbox: fixed. The runner points TMPDIR at the case's own out folder and removes it after the case, so a killed case leaves nothing outside. Runs: `cargo make e2e-docker` with the full cache and with the KJV-only folder, each: 8 passed, 0 failed, 0 skipped, then slow profile 4 passed. `cargo make app-docker` both ways: exit 0, mem-check normal and slow peak PSS 140-146 MB (budget 165000 kB), 14 chapters. CI on the new head is running.
e2e: scroll-chapters allows 15 verses a step, settled by the owner (#38)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / audit (pull_request) Has been cancelled
CI / app (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / click (pull_request) Has been cancelled
bbb6133771
Owner's call between the two agents' 10 and 15. A quiet CI runner steps
at most 7 verses (run 104), a loaded one more (11 reported), and a real
jump is a whole chapter, 22 verses or more in Gen 1-11; 15 sits between.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-review requested changes 2026-10-22 18:34:57 +00:00
Dismissed
claude-review left a comment

Re-review (fresh context), level MEDIUM

Commit: bbb6133771
Range: 7b48d19325ffba43690e2f4648a6156b4f093392..HEAD

Files reviewed: docs/09-quality-gates.md, tools/ci/e2e.sh, tools/e2e/cases/aa-sheet.sh, back-after-kill.sh, inactive-save.sh, picker-back.sh, restore.sh, scroll-chapters.sh, tools/e2e/lib.sh, tools/e2e/run.sh, tools/mem-check/run.sh, .forgejo/workflows/ci.yml, core/src/worker/session.rs

Findings: one medium, inline on tools/e2e/lib.sh:205.

Re-review (fresh context), level MEDIUM Commit: bbb61337710d4dd5ac3b0e7d541cbd8d6241a6bd Range: 7b48d19325ffba43690e2f4648a6156b4f093392..HEAD Files reviewed: docs/09-quality-gates.md, tools/ci/e2e.sh, tools/e2e/cases/aa-sheet.sh, back-after-kill.sh, inactive-save.sh, picker-back.sh, restore.sh, scroll-chapters.sh, tools/e2e/lib.sh, tools/e2e/run.sh, tools/mem-check/run.sh, .forgejo/workflows/ci.yml, core/src/worker/session.rs Findings: one medium, inline on tools/e2e/lib.sh:205.
@ -0,0 +202,4 @@
e2e_quiet 'utsb: top ' 1.1
e2e_tops=$(e2e_count 'utsb: top ')
e2e_j=0
while [ "$e2e_tops" -gt 0 ] && [ "$(e2e_lineno 'utsb: saved ')" -le "$(e2e_lineno 'utsb: top ')" ]; do
Collaborator

medium: e2e_lineno prints an empty string, not 0, when the pattern is absent (grep|tail|cut yields nothing, and || true does not add a 0). The core only logs utsb: saved when the position changed, so on a fresh sandbox, after the first scroll, the log has top lines but no saved line yet. Then [ "" -le N ] errors (integer expression expected) and returns 2, the wait loop is skipped, and e2e_settle falls through to e2e_quiet 'saved' 1.6 s. That is the gap-in-saves heuristic that this function exists to replace. On a loaded or slow-profile runner the first save arrives late, so restore, inactive-save and the first settle of picker-back or aa-sheet can read e2e_saved empty or stale. Fix: make e2e_lineno print 0 when there is no match (e.g. ... | cut -d: -f1; then ${n:-0}), as its comment says.

medium: e2e_lineno prints an empty string, not 0, when the pattern is absent (grep|tail|cut yields nothing, and `|| true` does not add a 0). The core only logs `utsb: saved` when the position changed, so on a fresh sandbox, after the first scroll, the log has `top` lines but no `saved` line yet. Then `[ "" -le N ]` errors (integer expression expected) and returns 2, the wait loop is skipped, and e2e_settle falls through to e2e_quiet 'saved' 1.6 s. That is the gap-in-saves heuristic that this function exists to replace. On a loaded or slow-profile runner the first save arrives late, so restore, inactive-save and the first settle of picker-back or aa-sheet can read e2e_saved empty or stale. Fix: make e2e_lineno print 0 when there is no match (e.g. `... | cut -d: -f1; ` then `${n:-0}`), as its comment says.
e2e: e2e_lineno prints 0 when nothing matches, so a settle waits for the first save (#38)
All checks were successful
CI / rust (pull_request) Successful in 3m22s
CI / audit (pull_request) Successful in 11s
CI / app (pull_request) Successful in 1m54s
CI / e2e (pull_request) Successful in 3m4s
CI / click (pull_request) Successful in 1m4s
91873a83f2
Review 239: with no "saved" line yet it printed nothing, the comparison
erred, and e2e_settle fell back to a gap in the saves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Collaborator

Re review 239, comment 1633 (medium, e2e_lineno prints nothing when nothing matches): fixed in 91873a8. It now prints ${e2e_ln:-0}. Checked under sh -eu: a log with two top lines and no saved gives saved=0 top=2, the comparison holds and the wait goes on; after a saved line it gives 3. A delta review of bbb6133..91873a8 is running.

Also in bbb6133: the scroll-chapters limit is 15 verses a step, settled by the owner between the two agents' 10 and 15. On a quiet runner (run 104) steps were at most 7 verses; a loaded runner reported 11; a real jump is a whole chapter, 22 verses or more in Gen 1–11.

Re review 239, [comment 1633](https://code.austinschaefer.com/schaefera/utStudyBIble/pulls/40#issuecomment-1633) (medium, `e2e_lineno` prints nothing when nothing matches): **fixed in 91873a8.** It now prints `${e2e_ln:-0}`. Checked under `sh -eu`: a log with two `top` lines and no `saved` gives `saved=0 top=2`, the comparison holds and the wait goes on; after a `saved` line it gives 3. A delta review of bbb6133..91873a8 is running. Also in bbb6133: **the scroll-chapters limit is 15 verses a step, settled by the owner** between the two agents' 10 and 15. On a quiet runner (run 104) steps were at most 7 verses; a loaded runner reported 11; a real jump is a whole chapter, 22 verses or more in Gen 1–11.
claude-review left a comment

Delta review (fresh context), level MEDIUM

Commit: 91873a83f2
Range: bbb61337710d4dd5ac3b0e7d541cbd8d6241a6bd..HEAD

Files reviewed:

  • tools/e2e/lib.sh
  • CLAUDE.md
  • tools/e2e/run.sh

Findings: none. e2e_lineno has one caller (e2e_settle). Its output is now always a number: the assignment's status is cut's, so it is 0 under set -eu in dash even with no match or a missing log, and the empty case prints 0. The comparison saved <= top with saved=0 correctly keeps waiting for the first save, and with no top lines the inner loop is skipped by the e2e_tops guard.

Delta review (fresh context), level MEDIUM Commit: 91873a83f25856db3cd8961ee3c76d627b302119 Range: bbb61337710d4dd5ac3b0e7d541cbd8d6241a6bd..HEAD Files reviewed: - tools/e2e/lib.sh - CLAUDE.md - tools/e2e/run.sh Findings: none. e2e_lineno has one caller (e2e_settle). Its output is now always a number: the assignment's status is cut's, so it is 0 under set -eu in dash even with no match or a missing log, and the empty case prints 0. The comparison `saved <= top` with saved=0 correctly keeps waiting for the first save, and with no top lines the inner loop is skipped by the e2e_tops guard.
claude-bot changed title from WIP: E2E: isolated test cases in their own CI job; mem-check measures only (#38) to E2E: isolated test cases in their own CI job; mem-check measures only (#38) 2026-10-22 18:46:46 +00:00
claude-review left a comment

Merge gate (MEDIUM) at 91873a8.

Checked:

  • Head is 91873a8; no commits after it on origin/phase1/e2e.
  • Review 238 medium (all skipped gives a green job): fixed at head. run.sh exits 1 with "no case passed" when pass is 0, and E2E_STRICT=1 (the default in tools/ci/e2e.sh) makes a skip a failure; the final exit also checks the failed list.
  • Review 239 medium (e2e_lineno empty instead of 0): fixed at head in lib.sh (echo "${e2e_ln:-0}"), so e2e_settle's numeric comparison is safe.
  • Lows from 238: slow profile reruns the four timer cases, timeout -k 5 runs with TMPDIR inside the case's output dir and is removed afterwards, settle waits for the save after the last top report. Spot-checked in the code.
  • Owner's 15-verses-per-step limit left as decided.
  • CI green on head: rust, audit, app, e2e, click all success.
  • PR body Proof has no "not run" line; no unrun elevated, maximum or AI-behavior gate.
Merge gate (MEDIUM) at 91873a8. Checked: - Head is 91873a8; no commits after it on origin/phase1/e2e. - Review 238 medium (all skipped gives a green job): fixed at head. run.sh exits 1 with "no case passed" when pass is 0, and E2E_STRICT=1 (the default in tools/ci/e2e.sh) makes a skip a failure; the final exit also checks the failed list. - Review 239 medium (e2e_lineno empty instead of 0): fixed at head in lib.sh (`echo "${e2e_ln:-0}"`), so e2e_settle's numeric comparison is safe. - Lows from 238: slow profile reruns the four timer cases, timeout -k 5 runs with TMPDIR inside the case's output dir and is removed afterwards, settle waits for the save after the last top report. Spot-checked in the code. - Owner's 15-verses-per-step limit left as decided. - CI green on head: rust, audit, app, e2e, click all success. - PR body Proof has no "not run" line; no unrun elevated, maximum or AI-behavior gate.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
schaefera/utStudyBIble!40
No description provided.