Skip to content

fix(browse): declare lastConsoleFlushed to restore console-log persistence#1309

Open
yashkot007 wants to merge 1 commit intogarrytan:mainfrom
yashkot007:fix/declare-lastConsoleFlushed
Open

fix(browse): declare lastConsoleFlushed to restore console-log persistence#1309
yashkot007 wants to merge 1 commit intogarrytan:mainfrom
yashkot007:fix/declare-lastConsoleFlushed

Conversation

@yashkot007
Copy link
Copy Markdown

@yashkot007 yashkot007 commented May 4, 2026

Summary

flushBuffers() (server.ts:331) maintains a per-buffer cursor for console / network / dialog so it only appends new entries to each on-disk log on every interval tick. The console cursor is referenced + assigned in the function body — but the matching let lastConsoleFlushed = 0; declaration is missing. Only the network and dialog siblings are declared at lines 327-328.

Result: every 1-second flushBuffers tick (line 376) throws ReferenceError: lastConsoleFlushed is not defined, gets swallowed by the catch at line 369 ([browse] Buffer flush failed: …), and the console branch's append never runs. browse-console.log is never written in any production deployment since this regressed.

Root cause

Regression introduced by 1a100a2a "fix: eliminate duplicate command sets in chain, improve flush perf and type safety" — the flush refactor switched from Bun.write to fs.appendFileSync and added the lastConsoleFlushed cursor pattern alongside its network/dialog siblings, but missed the matching let declaration. Tests don't currently exercise flushBuffers, so the regression shipped silently.

How it surfaced

Found while stress-testing the daemon with 15 concurrent CLIs against cold state. The race surfaced this in one spawned daemon's stderr:

[browse] Buffer flush failed: lastConsoleFlushed is not defined
[browse] Buffer flush failed: lastConsoleFlushed is not defined
…repeated every second indefinitely

Verified by running the daemon against a real file:// page with console.log events:

  • in-memory ./browse console correctly returns the captured entries
  • .gstack/browse-console.log is never created on disk

After the fix, the same flow produces a 163-byte log file with the expected entries.

Fix

+let lastConsoleFlushed = 0;
 let lastNetworkFlushed = 0;
 let lastDialogFlushed = 0;
 let flushInProgress = false;

One line. Same pattern as the existing siblings.

Regression test

Added browse/test/server-flush-trackers.test.ts — a source-level guard following the terminal-agent.test.ts and dual-listener.test.ts pattern (read source as text, assert invariant, no daemon required).

The test extracts every last*Flushed identifier referenced inside flushBuffers() and asserts each one has a matching let X = 0; declaration at module scope. Catches the exact regression class — any future flush-perf refactor that adds a fourth buffer cursor (or copy-pastes the pattern without the matching declaration) will fail this before it ships.

The failure message is intentionally specific so a future contributor sees the fix path without reading the test:

\lastConsoleFlushed` is referenced inside flushBuffers but never declared at module scope with `let lastConsoleFlushed = 0;` — the interval will throw ReferenceError every tick and the corresponding on-disk log will never be written`

Test plan

  • New regression test fails on current main (verified before the fix), passes with the fix
  • bun test browse/test/server-flush-trackers.test.ts — 1 pass / 0 fail
  • bun run build — clean rebuild of all binaries
  • Manual smoke — spawn daemon → goto file:// page with console.log → wait 4s for flush interval → .gstack/browse-console.log now exists with the expected entries (163 bytes vs zero file before)

🤖 Generated with Claude Code


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

…tence

flushBuffers() references a `lastConsoleFlushed` cursor at server.ts:337
and assigns it at :344, but the `let lastConsoleFlushed = 0;`
declaration is missing — only the network and dialog siblings are
declared at lines 327-328.

Result: every 1-second flushBuffers tick (line 376) throws
`ReferenceError: lastConsoleFlushed is not defined`, gets swallowed by
the catch at line 369 ("[browse] Buffer flush failed: ..."), and the
console branch's append never runs. browse-console.log is never
written in any production deployment since this regressed.

Discovered by stress-testing the daemon with 15 concurrent CLIs against
cold state — the race surfaced the buffer-flush error spam in one
spawned daemon's stderr. Verified by running the daemon against a real
file:// page with console.log events: in-memory `browse console`
returns the entries, but `.gstack/browse-console.log` is never created
on disk.

Regression introduced by 1a100a2 "fix: eliminate duplicate command
sets in chain, improve flush perf and type safety" — the flush refactor
switched from `Bun.write` to `fs.appendFileSync` and added the
`lastConsoleFlushed` cursor pattern alongside its network/dialog
siblings, but missed the matching `let` declaration. Tests don't
currently exercise flushBuffers, so the regression shipped silently.

Fix:
  - Declare `let lastConsoleFlushed = 0;` next to `lastNetworkFlushed`
    and `lastDialogFlushed` (browse/src/server.ts:327)
  - Add a source-level guard test
    (browse/test/server-flush-trackers.test.ts) that fails any future
    refactor that adds a fourth `last*Flushed` cursor without the
    matching declaration. Same pattern as terminal-agent.test.ts and
    dual-listener.test.ts — read source as text, assert invariant, no
    daemon required.

Test plan:
  - [x] New regression test fails on current main, passes with the fix
  - [x] `bun run build` clean
  - [x] Manual smoke: spawn daemon -> goto file:// page with
        console.log -> wait 4s -> .gstack/browse-console.log now
        exists with the expected entries (163 bytes vs zero before)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant