Skip to content

release: v1.4.0 - #13

Merged
Gyanano merged 22 commits into
mainfrom
release/1.4.0
Sep 2, 2026
Merged

release: v1.4.0#13
Gyanano merged 22 commits into
mainfrom
release/1.4.0

Conversation

@Gyanano

@Gyanano Gyanano commented Sep 2, 2026

Copy link
Copy Markdown
Owner

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 (develop for integration, main for production); release gate and docs now require tagged commits on main (override via RELEASE_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) and FrameBus (session/seq, Nagle-style batching, drop-oldest backpressure). The reader thread uses a single emit path, bounded join on disconnect, fatal-read connection_error, and POSIX write timeout. New Tauri commands get_logs_snapshot / epoch-aware clear_logs; a pump emits serial://frames to the UI. Unused deps (rusqlite, uuid, thiserror) are removed.

Frontend: useSerialLogs replaces default 100 ms get_logs polling with event push (rollback via localStorage 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.

Gyanano and others added 22 commits August 19, 2026 12:30
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 + 草稿态编辑修复
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@Gyanano
Gyanano merged commit 9e58d07 into main Sep 2, 2026
3 checks passed
@Gyanano
Gyanano deleted the release/1.4.0 branch September 2, 2026 13:07
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