Terminal stress test and instant cross-session search #18
Open
opened 2026-10-06 11:39:55 +00:00 by kayg
·
28 comments
No Branch/Tag specified
main
j470b-server-mesh-rejoin
mesh-compat-382
j444b-d381-key-wins-flood
j461b-macos-utun-reader-thread
j475b-remove-host-motion
fix-reconnect-new-link
j481-d380
dev
j479-mesh-soak
fix/j476-host-facts
j475-motion-pill-split
j470-mac-node-join
root-upgrade-d376
j474-review-merge
latency-targets-120hz
nightly-suite-shards
gotatun-pin-j469
macos-utun-reader-thread
fix-flood-echo-stall
wip/j416
motion-fast-ease-out
mesh-addhost-j259
takeover-close-terminals-d368
kbd-instant-followups
fix-trust-key-double-click
nightly-suite-partial-report
appwin-icons-j207
rusqlite-slice1
swipe-content-first-d374
mesh-mtu-381
addhost-instant-open
glass-contrast-d365-mock
glass-contrast-d365
signout-followups-442
fix-startup-toast-red
research-gotatun-matrix-j317
themes-sync-j304
fix-load-flakes
fix-nix-zig-patch
fix-compute01-browser-baseline
ratchet-size-baseline-419
predict-auto-d130
revoke-coverage-d367
nightly-suite-queue-timeout
nightly-browser-suite
fix-rustsec-2026-0459
fonts-ioskeley-obel
log-retention-d375
fix-kbd-no-anim-427
fix-dev-red-specs-2
takeover-proof-305-j205
wip/j410-server-pump
ui-consistency-d372
fix-osc52-clipboard
libghostty-vt-1.0
forget-retired-host-d369
j404-merge-426
fix-setup-lock-race
fix-touch-select-426
revoke-access-report-ui
fix-predictive-echo-specs
fix-selinux-agent-exec
wip/j395-checkpoint2
wip/j395
j391-review-scratch
ui-consistency-j195-deferred-rebased
fix-rustc-paths-421
decisions-wording-341
fix-install-suite-red
fix-dev-rtt-specs
fix-pending-removal-align
fix-privileged-skip
fix-install-suite-404
review-j368
mesh-dns-j254
revoke-access-report-d356b
revoke-privilege-round5
fix-removal-confirm
review-j360
gotatun-rotation-367
deps-refresh-340
review-j354
review-J351
review-j350
addhost-takeover-d359
revoke-report-items-347
revoke-end-sessions-d362
review-j348
size-mesh-ssh-346
size-trim-337
revoke-access-diff-d356
j259-pre-rebase-b06c5a6
j305-ended-at-start-spec
addhost-sudo-consent
fix-layout-real-specs-411
fix-shell-open-411
fix-console-hosts-373
fix-shell-exit
fuzz-host-name-353
fix-host-details-410
macos-filter-j197
research-gotatun-tricks
revoke-p3-j216l
stale-state-pill
revoke-followups-j216k
revoke-progress-j216e
backup/macos01-20261106/lume/j197
backup/macos01-20261106/lume/appwin-icons-j207-stash0
backup/macos01-20261106/claude/stash-0
backup/macos01-20261106/claude/stash-1
backup/macos01-20261106/claude/J80-macos-s1
backup/macos01-20261106/claude/J80
backup/macos01-20261106/claude/J80-slice1-20261102
backup/macos01-20261106/claude/J16b-appwin-on-dev
backup/macos01-20261106/claude/appwin-launch-idle-146
backup/macos01-20261106/claude/J80-s1-run
wip/j259
trust-285-p3c
runtime-lock-j216f
mesh-ssh-p3-j175
tun-proof-p3b
trust-285-p3
terminal-polish-j271
tun-proof-p3
ssh-install-flakes-j216i
fuzz-fixes-j264
trust-285-a
trust-285-b
restart-oversized-fixture-j198
backup/macos01-20261106/lume/appwin-icons-j207
restart-bound-j216h
up-preflight-p3-j198
backup/macos01-20261106/lume/j251
up-preflight-j198
wip/up-preflight-j198-j245-p2
wip/up-preflight-j198-j245-p1
agent-fsync-offloop-j196
wip/up-preflight-j198-j245
settings-offscreen-j231
wip/up-preflight-j198-j226-inspection
wip/j103f
themes-j206
wip/up-preflight-j198-j226
flakes-j216c
backup/macos01-20261106/claude/j197
flakes-j216b
backup/macos01-20261106/claude/j197-red
wip/up-preflight-j198-review
flakes-j216
backup/macos01-20261106/claude/appwin-icons-j207
engineering-j208b
appwin-mock-j209
toast-stack-j165
engineering-j208
decisions-d351
decisions-d350
decisions-d349
appearance-presets-mock-j129
decisions-d348
docs-audit-spec
doc-coverage-baseline-raise
decisions-d347
decisions-d346b
decisions-d346
j88h-profile
ui-consistency-j195-deferred
ui-consistency-j195
engineering-practices-j194
preferred-login-ui-j166
signin-pools-263-j174
macos-node-265-s1
decisions-d345
decisions-d344
proxy-cgroup-j164
verify-quick-fuzz-329
proxy-start-io-j168
timing-flakes-j163
up-263-s1
mcp-events-j147
verify-quick-fuzz-j158
proxy-p3-j159
agent-resource-j157-detect
wip/j103d-final
remote-cancel-hang-j155
proxy-traefik-281-j62d
j149-verify-quick
proxy-traefik-281-j62b
j150-drop-unnamed
wip/j79d-red-r4
wip/j103d-d332
rootless-toast-j142
wip/j103d-head
wip/j103d
j125c-mcp
macos-build-j136
backup/macos01-20261106/claude/j136
wip/j79d-red-cli
wip/j79d-red-server
j121-link-liveness
j118c-tracer-failures
wip/j79c-head
release-desktop-j131
j124c-signed-macos
wip/j79c-red-p3
wip/j79c-red-p23
wip/j79c-red-p22
merge-j128-check
perf-deferred-j128
sidebar-toggle-260
j127-shortcut-changed-dot
j125-mcp
j118-tracer-failures
j126-account-summary
settings-sections-mock-j92
j120-pinch-lock
sidebar-292
backup/macos01-20261106/claude/j120
taste-2026-11-03
row-actions-242-215
backup/macos01-20261106/claude/stash-0-untracked
backup/macos01-20261106/claude/J80-265-s1-run
backup/macos01-20261106/claude/J80-macos-s1-20261102
j112-canvas-commands
ui-no-overshoot-scroll
fix-recovery-restart
backup/macos01-20261106/claude/stash-1-untracked
taste-2026-11-02
size-baseline-ratchet
machine-cards-structure-j108
j109-boot-copy-mockups
fix-dev-red
wip/up-263-s1
j95b-settings-rows
proxy-traefik-281
j95-option-rows
docs-human-j91
docs-keys-palette
fix-flood-1013-270-j38d
mesh-ssh-s1
mesh-ssh-s0
addhost-d291-tunnel
test-stability-load
mesh-relay-220
repro-296
shim-thp-off-24
mesh-pins-258-v2
mesh-dns
signin-d311-merged
docs-pages
ui-size-283
fix-ui-batch-specs
wip/j12b-edge-update
gate-on-arm
fix-rename-sync-293
trust-285-j60b
fix-focus-ring-clip
integ-ui-1101
edge-update-v2
signin-d311
taste-2026-11-01
layout-per-tab-250
ui-approved-splitopt-224
ui-approved-splitopt-224-on-dev
icon-text-centre-282
ui-approved-189-212-216
research-reverse-proxy
transfer-budget-320
review-mesh-pins-258-r2
sidebar-pill-259
review-mesh-relay-220
wip/j12-edge-update-v2
nix-package
status-crash-loop-237
fix-dev-test-failures
fix-fixture-socket-path
wip/mesh-relay-220-pre-dev-advance-rebase
fix-canvas-side-clip
research-head-to-head
frosted-real-256
review-mesh-pins-258
wip/mesh-relay-220-pre-final-rebase
review-layout-per-tab-250-r2
broad-suite-triage
nix-devshell
review-status-crash-loop-237-r3
wip/nix-devshell-pre-p3
taste-frosted-real
wip/code-serve-demo-2026-10-30
wip/code-serve-glass-2026-10-30
wip/code-serve-clusters-2026-10-30
wip/code-merge-release94-dev-2026-10-30
wip/rproxy-delta-scratch-2026-10-30
wip/stale-note-257-staged-2026-10-30
wip/d241-size-staged-2026-10-30
review-broad-suite-207
wip/mesh-pins-258-pre-split
wip/mesh-relay-220-pre-rebase
mesh-measure-220
plan-211-update
review-edge-autoupdate-r3
perf24-reconnect
review-stale-note-r2
release-prod-live
d241-shell-marker
review-mesh-pins-server-258
review-revocation-r3
review-setup-token-r2
review-sync-journal-r3
wip/review-mesh-pins-258-prune-review-1995fee46
frosted-scroll-256
sync-journal-r3
revocation-per-account-wip
review-tokio-asyncfd-0386
review-sync-p3s
wip/stash-8by64-stash0-2026-10-30
mesh-drag-r2
setup-token-data-wip
release-9-4
auth-busy-1013
mesh-view-overlap
sync-p3s
review-auth-busy-wake
review-readd-r8-wip
mesh-drag-bounds
audit-auth-93
app-windows-stream-start
review-authority-cap-r3
app-windows-r7-measure
readd-minimal-r6
readd-minimal-r5
app-windows-r7-soak
readd-minimal-r4
app-windows-r7
app-windows-r6
readd-minimal-r3
readd-minimal-r2
readd-minimal
merge-release8-dev
review-busy-page-liveness-r2
review-busy-page-liveness
mesh-view-trim
review-authority-read-retry-r2
review-remove-uninstall-r2
release-retry-reattach
release-retry
review-remove-uninstall
review-authority-read-retry
app-windows-ship
mesh-autoswitch-p2
mesh-ssh
mesh-relay
mesh-macos-node
screen-and-control
session-labels
review-real-logins-r5
review-real-logins-r4
review-real-logins-r3
shim-memory-r2
review-real-logins-r2
shim-memory
shadow-addhost-instant
shadow-real-logins
shadow-same-session-flood
shadow-prod-perf-fix
hosts-from-server
app-windows-real
app-windows-transport
release-prod-6w
mesh-policy-verify
quiet-close-toast
dev-merge-r4
review-mesh-agent-transport
review-app-windows-transport
settings-roundtrip
review-release-pipeline-r4
mesh-agent-transport
ended-strip-fix
review-audit-ca-update-d244
settings-rows
phone-width
signout-clear
fix-restart-tests
dev-merge-rp
signer-hardening
review-audit-ca-update
terminal-fidelity
review-audit-ca-update-wip
mesh-integrate
review-mesh-agent-transport-515d3712
review-mesh-dataplane-feec1988
mesh-dataplane
signout
research-canvas-node
wip/review-renderer-cost
wip/review-terminal-fidelity
padlock-glyph
review-release-pipeline-2e95b689
phone-polish
sidebar-polish
inbox-generic
review-mesh-dataplane-378d4055
prod-batch
ui-inbox
ui-ca-unlock
ui-machine-sections
review-mesh-dataplane-a5f744fb
tls-session-prod
session-bounds-prod
fix-dead-session
session-bounds
tls-session
palette-polish
shortcuts-d222
research-appmeta
phone-gutter
ui-centre-button
wip/ui-centre-button
wip/tls-session
review-addhost-breakit
ui-platform
renderer-cost
remote-agents
mesh-api
ssh-bootstrap
prod-hotfix2
prod-fixes
review-remote-agents
review-mesh-dataplane
session-life
research-browser
review-mesh-api
research-capture
review-mesh-api-round3
review-mesh-api-round1
gate-stability
review-gate-stability
review-relay-direct
review-mesh-api-findings
proto-sessions
font-picker
proto-addhost
proto-windows
mesh-core
latency-gate
research-bsd
research-discovery
keytray-mods
mock-core
ui-tweaks
fix-motion-sel
fix-motion
integrate2
fix-robust
t-web
t-server
vt-ghostty
fix-snap-echo
t-web-auth
review-vt2
t-agent
lane-protocol
lane-shim
lane-auth
s1-base
s1-contracts
s1-workspace
No results found.
No labels
launch-qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
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
kayg/infraternal#18
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Owner request (2026-10-06): stress the terminal with a "behemoth" of output: mixed text, Unicode and emoji, and binary data. Output of any kind must scroll extremely fast. Scrollback must stay searchable. Binary output is left out of search by default, so the index stays small and fast. With about 50 SSH panes open on many hosts, finding one command must be instant.
Part 1 (job
stress-render): fixtures plus measurements of ghostty-web in the core-screen mockup: maximum parse throughput, frames during a flood, input latency during a flood, memory, and the behaviour on binary data.Part 2: the search design. The grill questions are in this thread. The decisions follow the owner's answers.
Starting terminal stress test on branch spike-renderer, based at
4560d9dd64. Current branch HEAD:af2c652948.Fixture evidence: the committed generator emits exact decimal sizes (behemoth 50,000,000 B; binary and mixed 20,000,000 B each). Local generation verified behemoth as valid UTF-8 with 228,916 lines and a 24,664-character longest line. Mixed intentionally becomes invalid UTF-8 at its first 128,000-byte binary block (offset 3,872,000).
Image gate passed: podman build produced ccc8b9d461fe; a 256 MiB read-only container populated /root/demo/stress with behemoth.txt=50,000,000 B, binary.bin=20,000,000 B, mixed.txt=20,000,000 B, bash.elf=1,265,648 B (ELF magic 7f 45 4c 46). Restarted spike-renderer-live.service; it is active and both 47341 and the 47351 mockup proxy return HTTP 200.
Confirmed renderer failure: the unmodified mockup terminal (only an in-memory terminal handle probe) crashes Chromium 61 ms after Enter on ; only 86,552 of 50,000,000 payload bytes / 23 binary frames reached the page. The target crash prevents prompt, frame, heap, input-echo, and final-screenshot capture. Reproduction data is in spikes/stress/.run/live-browser.json; crash screenshot also fails with . This is present without the performance probes.
Confirmed renderer failure: the mockup terminal (only the in-memory terminal handle probe) crashes Chromium 61 ms after Enter on cat behemoth.txt; only 86,552 of 50,000,000 payload bytes (23 binary frames) reached the page. The target crash prevented prompt, frame, heap, input-echo, and final-screenshot capture. Reproduction data: spikes/stress/.run/live-browser.json. page.screenshot also failed with Target crashed. This occurred without performance probes.
Finding: the disposable PTY WebSocket is not the observed behemoth bottleneck. Reading 50,000,000-byte behemoth.txt without a browser terminal delivered 50,228,984 bytes over 12,879 frames direct (3,982.7 ms, 12.55 MB/s) and 50,228,984 over 13,067 frames through the mockup Bun proxy (3,027.8 ms, 16.51 MB/s). The in-page terminal previously crashed Chromium after 86,552 payload bytes; isolated offscreen ghostty parsing also crashes at its 64 KiB checkpoint. Evidence: spikes/stress/.run/proxy-throughput.json, spikes/stress/.run/live-browser.json, spikes/stress/.run/raw-parser.json.
Finding: a 4 KiB-window classifier threshold of 1% is clean on these fixtures when it marks binary if invalid UTF-8 bytes OR disallowed C0 bytes reach 1%; ESC, TAB, LF, and CR are excluded. Exact analyzer evidence: 0/12,208 behemoth text windows triggered (max invalid UTF-8 0.073%, max disallowed C0 0%); 4,883/4,883 random binary windows triggered (max 46.069% invalid UTF-8, 12.476% C0); 161/4,883 mixed-file windows triggered, including the embedded random regions. Repro: spikes/stress/analyze-fixtures.py spikes/stress/.run/fixtures.
Raw parser isolation (16 KiB crash checkpoints): Terminal.write() completed 209,715,200 bytes in 19,476 ms desktop (10.77 MB/s) and 61,418 ms on iPhone 15 Pro at 4x CPU throttle (3.41 MB/s). The other fixtures still crash Chromium; last fully completed checkpoints: desktop behemoth 81,920 B, binary 98,304 B, mixed 81,920 B; iPhone behemoth 81,920 B, binary 212,992 B, mixed 81,920 B. Sustained yes uses 1 MiB progress checkpoints to keep host instrumentation overhead bounded; write durations exclude checkpoint callbacks. No PTY/WebSocket is in the timed write loop.
Live mockup reproduction (second full matrix): desktop Chromium again crashed on cat behemoth.txt after 87,135 received bytes / 76 ms, cat binary.bin after 216,274 bytes / 727 ms, and cat mixed.txt after 81,660 bytes / 45 ms. This confirms the file-output crash is repeatable on the current running mockup; final prompt paint and end screenshot are unavailable because the Chromium target crashes.
Gate availability finding: the spike-renderer HEAD has no scripts/verify file and no Cargo.toml ( is empty; neither exists in the worktree root). s1-base contains the Rust gate dispatcher, but its Rust workspace is not present on this spike branch. I will attempt the required scripts/verify fast command at finish and report its exact result; the spike's Node/Python syntax checks and measured browser/parser gates are available here.
Extended desktop yes | head -c 200M result: at the 25-minute cap the page had received 248,600,214 WebSocket bytes (0.166 MB/s) and still had no natural prompt; Ctrl-C recovered the shell. During the flood: 23.17 fps, 466.8 ms longest frame, 8,336 gaps >50 ms, no >1 s gap, 10,601 long tasks >50 ms (875,341 ms total, 441 ms max). The 🧪 key was not sent to the WebSocket or painted within 25 minutes. Renderer RSS was 239,924 KiB after output and 243,052 KiB after scroll; screenshots were visually clean.
The 4x iPhone 15 Pro emulation reproduced the file-renderer failures: behemoth 86,602 received bytes / 1,062 ms, binary 233,560 bytes / 6,441 ms, mixed 86,575 bytes / 943 ms. The page target crashed in each case, so prompt paint, frame and memory results are unavailable; the screenshot attempts also failed with Target crashed.
The 4x iPhone flood hit the 25-minute cap without a natural prompt. Its active command WebSocket delivered 108,714,899 B (0.0725 MB/s over the full cap); the first observed close was about 7m38s after Enter, giving about 0.237 MB/s before disconnect. Six code-1006 WebSocket closes were recorded as the mockup auto-reconnected. The output screenshot shows repeated root prompts concatenated with ^C at the bottom, so the page visibly corrupts its session state after reconnect. No >1s frame gap or canvas context loss was recorded; 🧪 was not sent or painted. RSS: 218,636 KiB after output, 226,716 KiB after scroll.
Finished on branch spike-renderer at
37c5e7dbfd. Report and four reviewed flood screenshots: spikes/stress/RESULTS.md. All six live file-fixture runs crashed Chromium; the three fixture types also crashed isolated Terminal.write after 82–213 KiB. Desktop yes received 248,600,214 bytes over 25 minutes (0.166 MB/s), with no prompt or input echo. iPhone emulation received 108,714,899 bytes (0.072 MB/s full-window), recorded six code-1006 closes, and showed reconnect prompt corruption. Direct/proxy behemoth samples were 12.55/16.51 MB/s. Binary heuristic flagged 0/12,208 behemoth windows, all 4,883 binary windows, and 161 injected-binary mixed windows with no text-only false positives. Fixture scan and JS/Python syntax checks passed. Required gate output (verbatim): zsh:1: no such file or directory: scripts/verify (exit 127; scripts/verify is absent on this spike branch).Orchestrator: showstopper found. ghostty-web 0.4 takes down the Chromium renderer process within the first ~80–220 KB of the behemoth, binary and mixed fixtures (desktop and phone), even in the isolated
Terminal.write()path without the network. Longy\nfloods survive. This affects DECISIONS 14 (renderer) and DECISIONS 94 (libghostty-vt in the shim, the same VT core in native form). Follow-up jobghostty-crash: reduce the input to a minimal reproducer, find out if the WASM VT core or the JS renderer is at fault, run the same input through native libghostty-vt (the engine of the shim lane) and through xterm.js, and draft an upstream issue. The other findings are recorded for the tracer: the live path at 0.166 MB/s against 10.8 MB/s for raw write (no flow control in the mockup), no input echo during a flood, the 1006 reconnects on the phone without resume, and a binary heuristic with 0 false positives on Unicode text.Starting renderer crash minimisation on branch spike-renderer. Starting HEAD:
37c5e7dbfd; merge-base/base SHA:4560d9dd64. Scope: spikes/stress/crash/.Starting crash minimization and attribution on branch spike-renderer; base SHA
37c5e7dbfd. I’ll work under spikes/stress/crash/.Upstream check (coder/ghostty-web), before the crash job reports. Open items that may be our crash:
Plan (owner, 2026-10-06): if the cause is in the library, we send a fix PR upstream (or add our reproducer to an existing issue or PR). First test whether 0.5.0-rc.0 or PR #142 already fixes the reproducers.
Finding: isolated Ghostty-WASM failure reproduces before network transport. The exact parser-page path completes 16,384 B of behemoth.txt, then Chromium crashes while writing the 81,920–98,304 B interval; spikes/stress/crash/probe.mjs records WASM memory at 11.6 MB and renderer RSS below 150 MiB before exit. Node 22 running ghostty-web 0.4.0's bundled WASM without a DOM/canvas also throws RuntimeError: memory access out of bounds on that interval (spikes/stress/crash/wasm-core.mjs). This currently points at WASM VT core, not canvas-only or host OOM; exact byte/content reduction is in progress.
Finding: the behemoth failure is content-dependent. Replacing all combining marks with ASCII makes the 82,541 B prefix complete; retaining only U+0301 COMBINING ACUTE ACCENT or only U+0651 ARABIC SHADDA still traps the bundled WASM. Removing ANSI CSI, removing the long trace, or replacing emoji/symbols alone removes or changes less relevant content; the long trace by itself completes. Controlled variants and results are in spikes/stress/crash/reduce-content.py and .run/content-results.json (ignored runtime evidence). I’m reducing mark count/context next.
Finding: content bisection now has byte-exact first failing prefixes: behemoth 82,541 B (82,540 B completes), mixed 82,144 B (82,143 B completes), binary 106,342 B (106,341 B completes), using 16 KiB writes. A direct Node call to ghostty_terminal_write with one reused WASM input buffer still traps at the same offsets; it bypasses Terminal.write's per-call JS allocation/free and has no DOM/canvas. This attributes the fault to the bundled WASM terminal core, not its canvas or per-write wrapper allocation. Peak browser RSS remained ~148 MiB and WASM memory ~11.6 MB before process exit; no OOM evidence.
Native check: libghostty-vt 0.2.2 via the crate's Rust binding and Zig 0.15.2 passed all three minimized-prefix candidates, all complete fixtures, and an 80x24→205x56 resize before input. It also passed a drop/recreate canary after each feed. Full-fixture results at 205x56 with 64 MiB max_scrollback: behemoth 50,000,000 B in 1,230 ms (40.65 MB/s), peak RSS 117,360 KiB including the loaded input file; binary 20,000,000 B in 1,038 ms (19.28 MB/s), peak 29,776 KiB; mixed 20,000,000 B in 545 ms (36.70 MB/s), peak 58,568 KiB. The 82,541 B text prefix, 106,342 B raw binary prefix, and 192,253 B browser-decoded binary prefix all completed; no native panic/trap/hang. These runs are on infraternal-dev, i9-9900K, 8 CPUs, load average 2.97, using release builds.
Finding — full xterm comparison: all three full fixtures completed without a renderer crash in xterm.js 5's DOM default and WebGL, using the 16 KiB write harness at 205×56 (Chrome 153.0.8010.12). Throughput, decimal MB/s: behemoth DOM 0.851 / WebGL 3.217; binary DOM 0.335 / WebGL 0.714; mixed DOM 1.050 / WebGL 3.279. DOM peak renderer RSS was 386,428 / 447,288 / 365,720 KiB; WebGL 260,828 / 242,140 / 276,796 KiB. Harness: spikes/stress/crash/probe.mjs; xterm uses the exact fixture bytes after the same streaming UTF-8 replacement decode. I also captured Chromium's SIGSEGV_ACCERR stack on the Ghostty repro; Crash Reports contained no minidump. One discrepancy under investigation: the new fixed-geometry iPhone probe passes 86,602 bytes while the existing raw-parser harness again crashes after 81,920 bytes.
Further minimization: the smallest content-controlled text trigger found is spikes/stress/crash/reproducers/minimal-combining-5679.bin (5,679 B; SHA-256 0047de6d657e0a1f69e16b9cdf8c6dc9343c98086c8b44df9276223f4bf3428f). It is 334 repetitions of 5a cc81 5a cc81 5a cc81 5a cc81 5a cc81 0d 0a, followed by 5a. The 5,678-byte prefix completes; adding that final Z traps both through Terminal.write() and direct reused-buffer ghostty_terminal_write in Node, and Chromium logs SIGSEGV_ACCERR at 205x56. It is valid UTF-8 with no escape sequences. Native libghostty-vt 0.2.2 release completes it (3.356 ms, peak RSS 4,292 KiB). This local reduction and replay are documented in spikes/stress/crash/RESULTS.md.
Additional checks: native libghostty-vt 0.2.2 completes the 106,342-byte first-failing raw binary prefix after resize (5.354 ms, peak RSS 7,580 KiB, follow-up canary passed). xterm.js 5.5.0 completes the exact 5,679-byte text reproducer in DOM (9.1 ms) and WebGL (7.7 ms), in addition to completing all three full fixtures in both modes. During review, a synthetic 16 KiB all-0xff chunk exposed a direct-probe buffer sizing hazard: decoded UTF-8 was 49,152 B for a 16,384 B allocation. The direct WASM probe now allocates and guards 3x chunk capacity; the synthetic payload completes, while both real WASM reproducers still trap. Details are in spikes/stress/crash/RESULTS.md.
Measurement correction from reviewer pass: the native probe's first timer started before terminal construction/resize, so its small-input write times included setup. A pre-fix ordering assertion failed; the timer now starts immediately before the first 16 KiB write, and the release cases were rerun. Updated results: behemoth 50 MB 1,285.939 ms (38.882 MB/s), raw binary 20 MB 921.948 ms (21.693 MB/s), mixed 20 MB 491.873 ms (40.661 MB/s), browser-decoded binary 36,255,730 B 636.964 ms (56.920 MB/s), minimal 5,679 B 1.647 ms, raw binary prefix 106,342 B 5.966 ms, and one-ESC variant 192,253 B 3.553 ms. All completed with follow-up canaries; peak RSS values and method are updated in spikes/stress/crash/RESULTS.md. Earlier native times in this issue thread are superseded by these corrected samples.
Content reduction within the repeated combining-row family: 333 rows plus final Z (5,662 B) completes; 334 rows plus Z (5,679 B) traps; 335 rows plus Z (5,696 B) traps. The 334 rows without the final Z (5,678 B) complete. This establishes the first failing row count for this controlled pattern, not a global minimum over arbitrary byte strings. The exact inputs are the pattern described in spikes/stress/crash/RESULTS.md; the 5,679-byte artifact remains unchanged.
Final result and renderer comparison:\n\n| Trigger | Component | Native affected? | xterm.js affected? | Recommended mitigation |\n|---|---|---|---|---|\n| Valid UTF-8: 334 rows of five Z+U+0301 clusters plus final Z; 5,678 B completes, 5,679 B traps | ghostty-web 0.4.0 bundled WASM VT write/state; reproduces in Node without DOM/canvas and direct ghostty_terminal_write | No. libghostty-vt 0.2.2 release completes with canary | No. Exact payload completes in DOM and WebGL; all full fixtures complete too | Keep arbitrary PTY writes off 0.4.0 until a patched stable build passes these artifacts; owner decides renderer policy |\n| Binary fixture: 106,342 raw bytes normalize to 192,253 UTF-8 bytes; retaining one context-dependent ESC still traps, replacing all ESC with x completes | Same bundled WASM write/state path | No. Raw prefix, normalized variant, and full fixtures complete | No. Full binary fixture completes in both modes | Same pending-fix mitigation; blanket escape stripping is unsafe |\n\nAttribution: the text trap is RuntimeError: memory access out of bounds in Node and Chromium logs SIGSEGV_ACCERR. WASM memory was 10,158,080 B and Node RSS about 74 MB after trap; Chromium started near 131,176 KiB renderer RSS. No OOM evidence or minidump. Native release completed all three fixtures and the reproducers with follow-up canaries. xterm DOM rates were 0.335–1.050 MB/s at 365,720–447,288 KiB peak RSS; WebGL was 0.714–3.279 MB/s at 242,140–276,796 KiB.\n\nMobile note: existing iPhone emulation crashes on full behemoth at 81,920 B. The focused probe completes the 5,679 B trigger at fitted 56x41, but crashes at 205x56; the geometry/harness discrepancy remains unresolved.\n\nNo matching upstream report was found; draft only at spikes/stress/crash/UPSTREAM-ISSUE.md.\n\nFinish: branch spike-renderer head
ddd446d9bd. Available checks passed: JS syntax, Python syntax, Rust format, release build, full diff check. Required gate output verbatim: zsh:1: no such file or directory: scripts/verify (scripts/verify fast exited 127 because this branch has no scripts/ directory).kayg referenced this issue2026-10-28 17:53:56 +00:00