Skip to content

fix(native): reduce startup probe latency after DA1#241

Merged
RtlZeroMemory merged 2 commits intomainfrom
fix/177-startup-terminal-probe-latency
Mar 4, 2026
Merged

fix(native): reduce startup probe latency after DA1#241
RtlZeroMemory merged 2 commits intomainfrom
fix/177-startup-terminal-probe-latency

Conversation

@RtlZeroMemory
Copy link
Owner

@RtlZeroMemory RtlZeroMemory commented Mar 4, 2026

Summary

  • resolves startup latency reported in Startup regression: ~1.4s delay in v0.1.0-alpha.21 due to terminal probing #177 when terminals do not answer XTVERSION
  • updates vendored Zireael detection loop to treat DA1 as a sentinel and stop probing after a short drain window (20ms)
  • keeps existing full timeout behavior for terminals that never answer DA1
  • updates Rezi native vendor pin and submodule pointer to the Zireael fix commit
  • adds changelog note under Unreleased bug fixes

Root Cause

zr_detect_probe_terminal() waited up to the full 500ms probe budget when one query (typically XTVERSION) had no response, even if DA1/DA2 arrived quickly. Since backend.start() blocks on engine creation, this delayed first render.

Fix Details

  • Add ZR_DETECT_DA1_DRAIN_TIMEOUT_MS and clamp read timeouts after DA1 is observed.
  • Parse accumulated probe bytes incrementally in-loop to detect DA1 early.
  • After DA1, perform only a short drain wait to capture trailing replies, then exit.

Validation

  • npm run check:native-vendor
  • npm -w @rezi-ui/native run build:native
  • npm -w @rezi-ui/native run test:native:smoke (deep checks skipped in non-TTY CI shell)

Dependency

Summary by CodeRabbit

  • Bug Fixes
    • Reduced startup delay on VTE-like terminal emulators by shortening terminal probe wait time after an early capability response, improving first-render speed and avoiding long stalls.

@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c2a37e2e-b69f-4ffc-b587-8f0138b2b95a

📥 Commits

Reviewing files that changed from the base of the PR and between 6d375e9 and 9620d0a.

📒 Files selected for processing (3)
  • packages/native/vendor/VENDOR_COMMIT.txt
  • packages/native/vendor/zireael/src/core/zr_detect.c
  • vendor/zireael
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/native/vendor/VENDOR_COMMIT.txt

📝 Walkthrough

Walkthrough

Implements a bounded DA1 drain timeout during terminal startup probing so the probe can exit early after a short DA1 drain window instead of waiting the full budget when XTVERSION never responds. Also updates the tracked vendor submodule commit and changelog entries.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Added bug-fix entry for DA1 drain timeout behavior; removed three prior bug-fix entries related to constraint/layout/override traversal.
Vendor Reference
packages/native/vendor/VENDOR_COMMIT.txt, vendor/zireael
Updated tracked vendor commit pointer to 97a7b907cc6c5a2886fdaef2ea82c8f9e337013e.
Terminal detection logic
packages/native/vendor/zireael/src/core/zr_detect.c
Added ZR_DETECT_DA1_DRAIN_TIMEOUT_MS, helper functions to track remaining DA1 drain budget, added DA1 sentiment tracking (da1_responded, da1_seen_ms, da1_drain_spent_ms), and modified probe loop/input accumulation to clamp per-iteration timeouts and honor the DA1 drain budget, allowing earlier exit when appropriate.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I sniff the bytes where DA1 hides,
I count the ticks, I skip the tides,
A tiny drain, a quicker start,
Less waiting slows the beating heart.
Hop—startup's bright, the terminal wakes! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: reducing startup probe latency after DA1 detection in the native terminal probing mechanism.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/177-startup-terminal-probe-latency

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/native/vendor/zireael/src/core/zr_detect.c (1)

868-907: ⚠️ Potential issue | 🟠 Major

DA1 drain window is not enforced as a strict 20ms wall-clock cap.

At Line [888]-Line [890], da1_drain_spent_ms only advances when n == 0. If reads continue returning bytes, the DA1 drain budget never decreases, so probe time can extend well beyond the intended drain window.

💡 Proposed fix (track elapsed time since DA1 observed)
-    uint8_t da1_responded = 0u;
-    uint32_t da1_drain_spent_ms = 0u;
+    uint8_t da1_responded = 0u;
+    uint64_t da1_seen_ms = 0u;

     while (true) {
       int32_t timeout_ms = zr_detect_read_timeout_slice(start_ms, timeout_spent_ms);
       if (da1_responded != 0u) {
-        const int32_t da1_budget_ms = zr_detect_remaining_da1_drain_budget(da1_drain_spent_ms);
+        const uint64_t now_ms = plat_now_ms();
+        const uint32_t da1_elapsed_ms =
+            (now_ms > da1_seen_ms) ? (uint32_t)(now_ms - da1_seen_ms) : 0u;
+        const int32_t da1_budget_ms = zr_detect_remaining_da1_drain_budget(da1_elapsed_ms);
         timeout_ms = zr_detect_clamp_timeout_budget(timeout_ms, da1_budget_ms);
       }
@@
       if (n == 0) {
         timeout_spent_ms += (uint32_t)timeout_ms;
-        if (da1_responded != 0u) {
-          da1_drain_spent_ms += (uint32_t)timeout_ms;
-        }
         continue;
       }
@@
       if (da1_responded == 0u) {
         zr_detect_parsed_t partial;
         zr_detect_parsed_reset(&partial);
         (void)zr_detect_parse_responses(collected, collected_len, &partial);
         da1_responded = partial.da1_responded;
+        if (da1_responded != 0u && da1_seen_ms == 0u) {
+          da1_seen_ms = plat_now_ms();
+        }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/native/vendor/zireael/src/core/zr_detect.c` around lines 868 - 907,
DA1's 20ms drain budget isn't enforced because da1_drain_spent_ms is only
incremented when plat_read_input_timed returns 0; fix by recording the
wall-clock time when DA1 is first observed (e.g., add a da1_responded_ts or
da1_drain_start_ms set when da1_responded transitions to non-zero inside
zr_detect_read loop) and on each loop iteration compute elapsed = now_ms -
da1_responded_ts and set da1_drain_spent_ms = (uint32_t)elapsed (or add to it if
you prefer monotonic accumulation) before calling
zr_detect_remaining_da1_drain_budget/zr_detect_clamp_timeout_budget so the DA1
drain budget decreases based on real elapsed time regardless of whether reads
return bytes; update types and initialization to match existing uint32_t time
variables and use the same time source used by zr_detect_read_timeout_slice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/native/vendor/zireael/src/core/zr_detect.c`:
- Around line 868-907: DA1's 20ms drain budget isn't enforced because
da1_drain_spent_ms is only incremented when plat_read_input_timed returns 0; fix
by recording the wall-clock time when DA1 is first observed (e.g., add a
da1_responded_ts or da1_drain_start_ms set when da1_responded transitions to
non-zero inside zr_detect_read loop) and on each loop iteration compute elapsed
= now_ms - da1_responded_ts and set da1_drain_spent_ms = (uint32_t)elapsed (or
add to it if you prefer monotonic accumulation) before calling
zr_detect_remaining_da1_drain_budget/zr_detect_clamp_timeout_budget so the DA1
drain budget decreases based on real elapsed time regardless of whether reads
return bytes; update types and initialization to match existing uint32_t time
variables and use the same time source used by zr_detect_read_timeout_slice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a2992db7-c327-46bc-9e9c-1be3ecc3a0ef

📥 Commits

Reviewing files that changed from the base of the PR and between be73751 and 6d375e9.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • packages/native/vendor/VENDOR_COMMIT.txt
  • packages/native/vendor/zireael/src/core/zr_detect.c
  • vendor/zireael

@RtlZeroMemory RtlZeroMemory merged commit 0dce821 into main Mar 4, 2026
29 checks passed
@RtlZeroMemory RtlZeroMemory deleted the fix/177-startup-terminal-probe-latency branch March 6, 2026 06:46
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