release: v1.4.0 - #13
Merged
Merged
Conversation
Point both READMEs at the latest release badge and drop the hand-edited changelog. CI fills release notes from commits since the previous tag.
- Drop unused Cargo deps: rusqlite (bundled), uuid, thiserror - Remove LogEntry.id (always None, SQLite-era leftover) from Rust and TS types - Remove unused imports/params/vars flagged by tsc strict mode
Runs on PRs to develop/main and pushes to develop. Rust job uses a frontend dist placeholder so tauri::generate_context! compiles without the real frontend build.
…y-net ci: Step 0 — PR 级安全网 + 死代码清理
RFC #3 Step 1 (pin behavior before rewiring): - New framing.rs: FrameSegmenter, a pure state machine replicating the legacy read loop's framing semantics, with find_delimiter / find_any_newline moved here as the single source of truth - serial_manager.rs: PortOpener trait + SystemPortOpener (serialport builder moved verbatim); connect() now opens via the seam - Golden tests drive the REAL reader thread through a scripted fake port, pinning current behavior including quirks: CRLF split across reads -> two frames; timeout flush uses strict '>'; Combined-mode timeout takes whole residue; reader death is silent (is_connected stays true, pending bytes lost) - Step 3 will fix - Direction derives PartialEq for assertions FrameSegmenter is test-only until Step 2 swaps the loop; the 3 dead-code warnings on its methods are intentional debt markers.
refactor(serial): Step 1 — 抽取 FrameSegmenter 纯状态机 + 端口注入缝 + golden 测试钉行为
RFC #3 Step 2: - Replace the four duplicated frame-emission blocks in connect() with a single emit_frame closure driven by FrameSegmenter (read loop ~330 -> ~120 lines). - Add max_frame_bytes hard cap (default 64 KiB): continuous streams with no delimiter are cut into cap-sized chunks during feed instead of accumulating unboundedly until an idle gap. Delimiters within the cap window still win. This is the only intentional behavior change. - Raw file tap stays before segmentation; read-error silent death pinned as Step 3 scope. Tests: 32/32 green (3 new framing unit tests + 1 scripted-port harness test for hard-cap cutting). cargo build warning-free.
refactor(serial): Step 2 读循环瘦身 + 帧硬切块
Exposed by hardware testing after RFC #3 Step 2: at 115200 8N1 a 2560 B / 100 ms scheduled send (25.6 KB/s) overruns the 11.52 KB/s line capacity and fails with 'Operation timed out' once the kernel TX buffer fills. - Backend: give the write handle a 1000 ms timeout on POSIX (timeout lives per-handle there, so the 50 ms read loop is unaffected). Windows shares COMMTIMEOUTS across cloned handles, so the write side keeps the builder value there. Per-poll timeout semantics mean borderline rates with bursts now drain instead of failing spuriously. - Frontend: SendPanel warns when a scheduled send's required rate exceeds 90% of the line capacity derived from baud/data/parity/stop bits, so physically impossible rates are flagged before the user hits timeouts. Remaining TX-queue work (write-behind thread, backpressure, failure reporting) tracked in #7 — needs RFC #3 Step 4 events as its channel.
feat(serial): POSIX 写超时加长 + 周期发送速率预警
… salvage RFC #3 Step 3: - disconnect() returns the reader JoinHandle and the (bounded, 500ms) join now happens OUTSIDE the big manager lock in the Tauri command, replacing the in-lock 200ms sleep. connect() joins any stale reader defensively, fixing the close->reopen EBUSY race. - Reader-thread death is no longer silent: the error is recorded, the next status poll (1s) flips is_connected=false with connection_error set, and the frontend toasts 'Connection lost: ...' once per transition. ConnectionStatus gains a connection_error field. - Pending partial frames are flushed (salvaged) on ANY reader exit instead of vanishing; new FrameSegmenter::flush(). - Fix scheduled-send zombie state: on disconnect or emptied payload the SendPanel switch now resets instead of showing 'scheduled active' with a dead timer. Tests: 34/34 green (golden_reader_death_is_silent_today replaced by reader_death_marks_connection_lost_and_salvages_pending; new disconnect_returns_joinable_handle_and_reconnect_is_immediate + flush_drains_pending_regardless_of_idle). Hardware-verified: unplug detection + toast + switch reset, replug reconnect, rapid disconnect/reconnect cycles, recording/export regression.
feat(serial): Step 3 读线程生命周期修复
Backend:
- New bus.rs: Frame {session, seq, dir, t_mono_ns, t_wall, Arc data} with
per-session seq from 1 shared by TX/RX; FrameBus with bounded
per-subscriber queues (drop-oldest + dropped_before prefix-gap
accounting) and Nagle batching (GUI_DEFAULT 16ms/64KiB/512 frames/4096
queue; lone frame for an idle consumer pushes immediately past a 4ms
anti-storm interval).
- Read loop and send_data publish frames after the buffer write
(dual-write coexistence: log buffer/text+raw recording/stats unchanged,
all golden tests intact).
- New get_logs_snapshot command {epoch, session, entries}; clear_logs
returns a bumped epoch.
Bridge (main.rs): app-lifetime pump thread consumes batches with bounded
blocking recv, decorates (display_text/timestamp) and emits
serial://frames; the wire DTO carries no raw bytes (seq/dir/len +
display text).
Frontend:
- useSerialLogs hook: snapshot alignment, incremental append with rAF
throttling, seq dedupe, session-change resync, epoch guard so a snapshot
racing a clear never resurrects entries, dropped_before placeholder rows,
trim mirroring the backend 1000-entry cap; LogViewer keys rows by
session-seq.
- Rollback switch: localStorage serialEventPush=0 restores the legacy
100ms polling loop.
Tests: 40/40 green (5 new bus unit tests incl. drop-oldest prefix-gap
accounting; harness test asserting contiguous seq across RX/TX through
the real reader thread). Hardware-verified on FTDI loopback: burst
sending, clear-during-stream, search/autoscroll/counters, unplug.
feat(serial): Step 4 事件推送替代轮询(RFC #3 收官)
- Lower the interval floor from 100ms to 10ms (the event-push RX path keeps up now; the rate guard still warns when the line can't). - Fix mid-edit clamping: the input keeps a draft string while focused and only commits (clamped) on blur/Enter; Escape cancels. Typing '50' no longer snaps to the minimum after the first digit.
feat(ui): 发送周期下限 10ms + 草稿态编辑修复
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_71ac4e35-2bf6-42b5-94f7-31c3c03ccff8) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v1.4.0
Version bump 1.3.3 → 1.4.0 (version.json / Cargo.toml / tauri.conf.json / package.json 四件套对齐)。
本版本内容(自 V1.3.3 以来的 develop 合并)
Release notes 由 CI 根据两次 Tag 之间的提交自动生成。
Note
High Risk
Large changes to the serial read/write path, threading, and IPC contract, plus a production-branch and CI gate shift that affects every release and contributor workflow.
Overview
Release v1.4.0 bumps all four version files from 1.3.3 → 1.4.0 and ships the accumulated RFC #3 serial stack plus repo/process updates.
Repository & CI: Branching moves to standard git-flow (
developfor integration,mainfor production); release gate and docs now require tagged commits onmain(override viaRELEASE_GATE_PROD_BRANCH). Adds PR CI (ci.yml: Rust tests + frontend typecheck/build), CONTRIBUTING guides, and a release-notes job that fills GitHub Release bodies from commits since the previous tag. READMEs drop hand-maintained version history in favor of the release badge and generated notes.Serial core (Rust): Introduces
FrameSegmenter(bounded 64 KiB frames, golden tests) andFrameBus(session/seq, Nagle-style batching, drop-oldest backpressure). The reader thread uses a single emit path, bounded join on disconnect, fatal-readconnection_error, and POSIX write timeout. New Tauri commandsget_logs_snapshot/ epoch-awareclear_logs; a pump emitsserial://framesto the UI. Unused deps (rusqlite, uuid, thiserror) are removed.Frontend:
useSerialLogsreplaces default 100 msget_logspolling with event push (rollback vialocalStorage serialEventPush=0). Connection lost toasts, stable log keys (seq/session), scheduled-send 10 ms–60 s interval with draft editing, line-capacity rate warning, and special-character display off by default.Reviewed by Cursor Bugbot for commit af8cccc. Bugbot is set up for automated code reviews on this repo. Configure here.