#109945 replaced the readFileSync(fd) call in readWorkspaceFileWithGuards
with readFileDescriptorBounded, which consumes the descriptor via fs.read.
The two transient-read tests still injected EAGAIN through readFileSync,
so the fault never fired: one asserted a retry that never happened and the
other asserted missing=true while the real read succeeded. Inject at the
fs.read seam instead; retry classification in prod is unchanged and the
full file passes 58/58 again.
* fix(mantis): bound upload error response bodies
Replace unbounded response.text() on non-ok upload error paths with
readBoundedResponseText (64 KiB cap). Only swallow the size-exceeded
diagnostic; propagate signal aborts and other failures so timeouts
during body reading are not masked as generic upload failures.
- Import shared readBoundedResponseText from scripts/lib/bounded-response.mjs
- Add MANTIS_UPLOAD_ERROR_BODY_MAX_BYTES constant (64 KiB)
- Catch only size-exceeded errors; re-throw timeouts and stream errors
- Add test: oversized body bounded at 64 KiB
- Add test: signal abort during body read propagates correctly
- Add test: small error body within bound reads normally
* fix(mantis): contextualize bounded upload failures
Co-authored-by: 胡根深 0668000903 <hu.genshen@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(auto-reply): bound AGENTS.md read in post-compaction context
readPostCompactionContext read the entire AGENTS.md with an unbounded
fs.readFileSync even though it only extracts a small (<=1800 char) section
for the continuation prompt. A pathologically large AGENTS.md forced an
unbounded allocation at compaction time. Use readFileDescriptorBoundedSync
with a 2 MiB limit (matching the workspace bootstrap file limit) and skip
the file with a warning when it exceeds the bound, instead of reading it all.
* fix(agents): bound workspace bootstrap reads
Co-authored-by: 琚耀辉0668001366 <ju.yaohui@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(zai): keep probe deadline through stalled error-body reads
Fixes an issue where Z.AI endpoint detection could hang indefinitely
when a probe returned error headers and then stalled on the error
response body. The previous helper cleared the AbortSignal as soon as
fetch resolved headers, so a never-chunking error body bypassed the
probe deadline.
Keep one AbortController deadline across the probe request and the
bounded error-body read, and pass a clamped chunkTimeoutMs into
readResponseWithLimit so a stalled error body fails closed inside the
remaining budget. The chunkTimeoutMs is clamped to the remaining
deadline after fetch returns headers, so the idle timeout does not
outlast the overall probe deadline.
Tighten the stalled-body test timing assertion from 5s to 2x timeoutMs
to verify the deadline is actually respected.
* fix(zai): enforce probe body deadline
Co-authored-by: NIO <noreply@github.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: NIO <noreply@github.com>
Avoid buffering unbounded provider error streams and cover the resource lifecycle with a deterministic cancellation contract.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(ui): call chat sessions threads and quiet the sidebar sections
Thread naming on every creation surface (new-thread page, draft row,
+ tooltips, untitled-thread fallback, New Chat guard toasts). The draft
placeholder now renders as the first item inside the Threads section and
genuinely expands a collapsed section so the header toggle stays honest.
Empty sidebar sections no longer render (Coding keeps its CLI-catalog
exception); expanded section headers reveal their chevron only on
hover/focus while collapsed headers keep chevron + count. The new-thread
button moves from the macOS titlebar strip into the sidebar brand row
next to the agent picker (bigger, offline-aware); the titlebar + renders
only while the rail is collapsed. Mobile drawer shows the new + as well.
* fix(ui): keep empty custom groups and the mid-drag Threads drop target
Empty-section hiding narrows to the Threads zone at rest: user-created
categories stay visible when empty (New group… creation and drag-into-group
flows depend on them), and an empty Threads section reappears while a
session drag is in flight so drag-to-unpin keeps its drop target.
* test(ui): drag-to-unpin targets the sessions surface
The empty Threads section only materializes mid-drag, so Playwright cannot
pre-resolve it as a drop target; the sessions container's drop handler owns
the unpin and sends {pinned:false} without a category reset.
Live verification showed dropped-CI PRs report mergeable=null and
mergeable_state=unknown indefinitely: the stuck merge-ref computation is
the same failure that dropped their CI, and close/reopen is what
un-sticks it. The pending-mergeability skip therefore made the primary
repair population permanently unsweepable (three real dropped PRs skipped
across three consecutive sweeps). Keep skipping computed conflicts; a
not-yet-computed conflict costs at most one budgeted re-fire.
* feat(cron): add unattended-run preamble to isolated agent turns
Isolated cron and hook agent turns received only the job tag, message,
and time line — no operating contract for unattended execution. Runs
ended in questions, plans, or bare acknowledgements (the runtime even
re-prompts once for interim acks). Append a static per-class preamble:
the final reply is the deliverable, HEARTBEAT_OK when idle, plain
failure statements. Trusted jobs additionally defer to the job's own
instructions on conflict and learn removal-only self-cleanup;
external-hook runs get only the common core so fenced webhook content
cannot use an override clause or a destructive affordance advertised in
the trusted suffix. Free-form job names stay out for the same reason.
* feat(cron): teach watcher authoring rules in the cron tool description
Trigger-script guidance covered only the return contract. Add the
operating rules that keep watchers trustworthy: fire on every
actionable state including failures (success-only watchers go silent
when broken), dedupe via returned state, keep scripts read-only with
actions in the payload, and make the fired message self-contained.
* docs: add The main session concept page and cross-links
* docs: precise memory-priming wording on the main-session page
* docs: update Control UI sidebar description to the Home and zones model