Skip to content

Stage 272: 3 PRs — #1493 sidebar cancel + #1495 state.db FD leak fix + #1492 P0 polish bundle (closes #1466 #1469 #1484 #1486 #1494; refs #1458 Bug #2)#1496

Merged
nesquena-hermes merged 8 commits intomasterfrom
stage-272
May 3, 2026
Merged

Stage 272: 3 PRs — #1493 sidebar cancel + #1495 state.db FD leak fix + #1492 P0 polish bundle (closes #1466 #1469 #1484 #1486 #1494; refs #1458 Bug #2)#1496
nesquena-hermes merged 8 commits intomasterfrom
stage-272

Conversation

@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Stage 272 release — 3 PRs

This release PR shepherds three contributor + self-built PRs to master with --no-ff merges.

Constituent PRs

Test posture

3866 → 3874 tests passing (+8: #1493's 3 + #1495's 4 + #1492's 1).

Pre-release Opus advisor passes

Initial 2-PR pass (#1493 + #1495): ship-as-is. Two non-blocking SHOULD-FIX deferred to follow-up.

Extended 3-PR pass (added #1492): ship-ready. All four risk areas check out:

  1. Fix fix(frontend): use URL origin for fetch/EventSource to support revers… #3's per-row Session.load_metadata_only(sid) perf cost is bounded (~5ms for 200 sessions, dominated by stat() early-returns).
  2. Fix fix(api): resolve model provider from config to prevent misrouting #4's setTimeout(0) race is real but benign — terminal state is always correct.
  3. Fix fix(frontend): use URL origin for fetch/EventSource to support revers… #3 (filesystem) and fix(sqlite): close state.db connections explicitly to stop FD leak in sidebar polling (#1494) #1495 (sqlite) don't interact — different resources, sequential execution.
  4. The sw.js regression test assertion "'/sw.js?v=" not in src is precise (the leading '/ makes it specific to the absolute form) and won't false-positive.

One Opus concern about CLI session IDs hitting load_metadata_only's [0-9a-z_] validator was investigated maintainer-side — real CLI session IDs use YYYYMMDD_HHMMSS_<6hex> format which fully matches the validator. Mooted by reality.

Release framing

Closes #1466
Closes #1469
Closes #1484
Closes #1486
Closes #1494
Refs #1458 (Bug #2 of 3)

bergeouss and others added 8 commits May 2, 2026 23:39
…ning

- #1481: Use absolute path for service worker registration to avoid
  <base> tag resolution on session pages causing JSON 404
- #1484: Fix tool-card expanded args readability — replace
  word-break:break-all with pre-wrap+break-word, add display:block
  so newlines and indentation are preserved
- #1486: Prefer WebUI JSON title over state.db title for CLI sessions,
  fixing rename-not-persisting after compression chain extension
- #1469/#1360: Add _programmaticScroll guard to distinguish
  programmatic scrolls from user scrolls, preventing the race
  condition where scrollIfPinned() re-pins after user scrolls up
… sidebar polling (#1494)

Production WebUI on macOS launchd reproduced an HTTP-unhealthy wedge after
#1483 closed the bootstrap supervisor double-fork: process alive, port
listening, every HTTP request reset by peer before a response. The reporter
(@insecurejezza) traced it to FD exhaustion — 366 open FDs on the wedged
process, 238 of them `~/.hermes/state.db`, `state.db-wal`, and `state.db-shm`.

Root cause: four sqlite callsites use `with sqlite3.connect(...) as conn:`.
Python's sqlite3 connection context manager only commits or rolls back on
exit; it does NOT close the connection. `/api/sessions` polling calls these
on every sidebar refresh, so each poll leaked one or more open state.db FDs
until the process hit macOS's soft FD limit and new sqlite3.connect() calls
inside fresh request handlers raised before any response bytes were written.

Fix: wrap each `sqlite3.connect(...)` in `contextlib.closing(...)` so the
connection is explicitly closed on scope exit, in addition to the auto-
commit / rollback semantics that `Connection.__exit__` already provides.

Callsites patched:
- api/agent_sessions.py:read_importable_agent_session_rows
- api/agent_sessions.py:read_session_lineage_metadata
- api/models.py:get_cli_session_messages
- api/models.py:delete_cli_session

Reporter's verification (post-patch, 100-request stress loop against
/api/sessions and /api/projects):

  batch=1 fd=92 state_handles=0
  batch=2 fd=92 state_handles=0
  ...
  batch=5 fd=92 state_handles=0

Pre-patch the same loop made FD count and state.db handle count climb
monotonically.

4 regression tests in tests/test_issue1494_state_db_fd_leak.py monkeypatch
sqlite3.connect with a tracking wrapper that records .close() calls and
assert every connection opened by each of the four functions is explicitly
closed. Verified to fail (catching the original bug) when the closing()
wrap is reverted: "leaked 5 of 5 sqlite connection(s) — context-manager-
only `with sqlite3.connect()` does not close. Wrap in contextlib.closing()."

This addresses Bug #2 of the umbrella issue #1458. Bug #3 (HTTP-unhealthy
wedge in the absence of FD exhaustion) remains open pending separate
diagnostic data — explicit scope discipline.

Closes #1494
Refs #1458 (Bug #2 of 3)

Co-authored-by: insecurejezza <[email protected]>
- Revert '/sw.js' back to relative 'sw.js' in serviceWorker.register()
  (static/index.html:50). The dynamic <base href> script resolves
  relative paths correctly for both root and subpath mounts.
  Absolute path breaks reverse-proxy installs at e.g. /hermes/.

- Add regression test test_index_sw_registration_uses_relative_path
  to prevent future absolute-path rewrites from silently breaking
  subpath-mount installs.

Addresses reviewer feedback on PR #1492 (review by @nesquena).
…ll pinning + sw.js relative-path regression test)
…ix + P0 polish bundle (#1466 #1494 #1469 #1484 #1486)

3 PRs in this batch (3866 → 3874 tests, +8):

- #1493 (@dso2ng) — sidebar Stop response cancels row's stream not active pane's (closes #1466, follow-up to #1480)
- #1495 (self-built; reported by @insecurejezza in #1494) — state.db connection FD leak in sidebar polling (closes #1494, addresses Bug #2 of #1458)
- #1492 (@bergeouss) — P0 bugfixes bundle: tool-card args readability + CLI rename persistence + scroll pinning + sw.js relative-path regression test (closes #1469 #1484 #1486)

This release closes Bug #2 of the umbrella issue #1458. Bug #1 was closed by v0.50.269 (#1483) + v0.50.270 (#1487). Bug #3 (HTTP-unhealthy without FD exhaustion) is the remaining work item.
@nesquena-hermes nesquena-hermes merged commit 6c3ff3f into master May 3, 2026
3 checks passed
@nesquena-hermes nesquena-hermes deleted the stage-272 branch May 3, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment