Skip to content

perf(rate-limit-guard): spool the statusline snapshot, drain it on a cadence (0.7.0) - #2521

Merged
kyle-sexton merged 3 commits into
mainfrom
perf/statusline-tee-spool
Aug 12, 2026
Merged

perf(rate-limit-guard): spool the statusline snapshot, drain it on a cadence (0.7.0)#2521
kyle-sexton merged 3 commits into
mainfrom
perf/statusline-tee-spool

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

What

The statusline tee fires on every assistant message and every refreshInterval tick, once per open session. Measured same-window here (Windows/MSYS, n=9): render.sh alone 234.4 ms, render.sh behind this wrapper 1047.1 ms. The wrapper dominates, and the dominant term inside it is process creation — a cost MSYS has no cheap primitive for.

0.6.x made that work cheaper (nine spawns to four). This release takes it off the render path instead.

A refresh now records one line to a per-session spool file using only bash builtins — zero external processes, zero subshells — and one elected refresh per 30 s drains the batch through the same tee_snapshot, unchanged.

Design

Per-session files with a truncating >, not a shared append spool. POSIX guarantees write atomicity for pipes up to PIPE_BUF and explicitly leaves regular-file concurrent-write behaviour unspecified. Through Cygwin/MSYS the observed no-interleave bound on appends is around a kilobyte, while statusline payloads are multiple kilobytes — and bash's buffered builtin output can split one large record across syscalls regardless. Atomicity therefore comes from file disjointness: no two writers ever share a file. A record torn by a kill mid-write fails fromjson in the drain and is dropped (covered by a test).

The filename is a shard key, never trusted data. session_id arrives in the harness payload. It must match ^[A-Za-z0-9._-]{1,64}$ and not begin with a dot, or it shards to the literal name misc. Traversal attempts, embedded quotes, 200-character values, has space, and JSON nulls are all covered by a test asserting nothing is written outside spool/.

Election is stamp-based and the elected refresh drains in-process. There is no timer to hang this on: Claude Code hooks are strictly event-driven and none fires on a schedule (hooks docs), an OS scheduler would mean three mechanisms across three platforms, and a resident lock-holder would have to be forked off a render — the exact cost being removed — and would be killed with it, since Claude Code cancels in-flight statusline scripts. So the renders are the clock. A herd collapses for one failed mkdir.

Bash 4.2 floor (%(%s)T is a 4.2 builtin). Below it — macOS bash 3.2, where fork is cheap and this problem does not arise — the previous synchronous path runs untouched. RLG_TEE_ASYNC=1 keeps its current behaviour on every version.

Design deviation from the brief

The election takes its own lock (spool/.drain.lock) rather than the existing snapshot lock. Two reasons, both load-bearing:

  1. tee_snapshot acquires and releases the snapshot lock through one global (TEE_LOCK). A drain holding that lock would make tee_snapshot burn its full retry budget (3× find + 3× sleep) and then rmdir the lock out from under its own caller.
  2. The snapshot lock's existing semantics — a window-bearing writer proceeds through a lock it could not take — must keep working. Gating the drain on that same lock breaks it, and the pre-existing assertion "held lock → window-bearing writer still writes" proves it.

tee_snapshot itself is untouched: same atomic temp-then-rename, same mkdir/rmdir concurrent-writer lock, same windowless-writer preservation check.

Verification

  • PASS=96 FAIL=0 — all 75 pre-existing assertions pass unmodified, plus 21 new. RLG_TEE_DRAIN_INTERVAL=0 is exported once near the top of the suite so existing cases keep their synchronous-visibility semantics; election is covered in dedicated cases that set the cadence per invocation.
  • Snapshot body byte-identical apart from captured_at, proven rather than asserted:
    diff <(jq -S 'del(.captured_at)' pristine.json) <(jq -S 'del(.captured_at)' patched.json)   # empty
    
    The body projection is now one shared jq function (rlg_body) called by both the live probe and the drain, so the two cannot drift.
  • Zero-fork claim proven by trace, not by reading the code. A test primes a scratch HOME with a fresh stamp, runs the tee under bash -x with BASH_XTRACEFD, and asserts that no jq|mkdir|mv|rmdir|find|date|uname|sleep|chmod|rm invocation and no command-substitution subshell frame appears before the passthrough.

Reader-visible change (inside the existing contract)

The contract file now trails the newest refresh on the machine by up to 30 s instead of being rewritten on every refresh, and captured_at is the observation time of the chosen record rather than the flush time — which is what lets a windowless refresh flush a window-bearing sibling's record without faking freshness. The reader contract budgets ten minutes of staleness and its operable floor values are unchanged. reference/reader-contract.md documents the cadence, the spool/ inventory, and the .tee-disabled marker.

Enablement gate

The gate still gates the write, but it cannot be evaluated on the render path — reading settings costs a jq. A drain that reads rate_limit_guard_enabled: false writes an epoch-stamped .tee-disabled marker and drops the spool; refreshes then stop recording on one builtin test. The marker expires, so re-enabling the plugin recovers without a restart.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lah151d2hvN4fBgMYdyjSH

Related

No linked issue — performance work with no tracked issue.

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 49s —— View job


Security review — /review:security-review

Reviewed only the diff introduced by this PR (git diff origin/main...HEAD), which spools the statusline tee off the render path into per-session files, drained on a 30 s cadence.

Task list

  • Gather context (PR diff, description, changed files)
  • Read statusline-tee.sh (new THE SPOOL section: _rlg_shard_name, acquire_drain_lock, _rlg_drain, _rlg_spool_dispatch), the updated reader-contract.md, and the new test cases
  • Hunt for injection, path traversal, TOCTOU/locking, and permission issues on the new code paths
  • Post findings

Findings

1 suggestion, posted inline on statusline-tee.sh#L826-L856:

  • SUGGESTIONspool/ is created with a bare mkdir and each per-session record is written with a plain > redirect, neither setting an owner-only mode. This relies entirely on the parent dir already being chmod 700 (asserted only when dir doesn't yet exist). tee_snapshot's target file additionally wraps its write in an explicit umask 077 subshell even though it's under the same 700 dir — a deliberate second layer, per that function's own comment. The spool now holds the same class of data (rate_limits, session_id, account fields) without that second layer, so any pre-existing rate-limit-guard directory that predates the chmod 700 hardening (older plugin version, hand-created directory) leaves spool records world-readable under a typical 022 umask, with no code path that ever re-asserts 700 on it afterward.

What held up well

The things this PR calls out as load-bearing security properties check out under adversarial reading:

  • Shard-key validation (_rlg_shard_name) anchors the regex (^[A-Za-z0-9._-]{1,64}$, no leading dot) and the extracted value is used only as a filename component, appended with a fixed .json suffix — no traversal, no collision with the reserved .last-drain / .drain.lock control files, confirmed by the new hostile-input test case (traversal string, embedded quote, 200-char id, leading-dot id, embedded space).
  • No shell injection surface: all jq invocations pass untrusted data via --arg/--argjson/stdin rather than string-interpolating it into the filter; all printf/read usage on attacker-influenced data (payload, session ids, stamp files) uses %s placeholders or regex-gated numeric parsing, never format-string or eval-style interpolation.
  • Locking is non-blocking and atomic (mkdir for both the snapshot lock and the new drain lock), and the drain re-reads the stamp under the lock before doing any work, closing the herd/duplicate-drain window the design doc describes.
  • Torn-record handling: a spool line that fails fromjson is dropped via try ... catch empty rather than corrupting or crashing the drain — covered by the torn-line test case.
  • No GitHub Actions/workflow files are touched in this PR, so no CI trust-boundary or pull_request_target/permissions surface to review.

No CRITICAL or IMPORTANT findings.
· branch: perf/statusline-tee-spool

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aad6de84ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/rate-limit-guard/scripts/statusline-tee.sh
Comment thread plugins/rate-limit-guard/reference/reader-contract.md Outdated
Comment thread plugins/rate-limit-guard/scripts/statusline-tee.sh
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Last security-reviewed head: c2a48098b198085e23ad7029ab20292e326ccd57. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 4m 49s —— View job


Code review — PR #2521

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Check skip gate (PR is open, non-draft, substantive — proceeded)
  • Review statusline-tee.sh changes
  • Review statusline-tee.test.sh changes
  • Review docs (reader-contract.md, CHANGELOG.md, plugin.json)
  • Post findings

Scope: this repo runs a dedicated claude-security-review lane, so this review stays in the code-review lane (correctness, design, error handling, tests, docs) and leaves injection/authorization/credential concerns to that lane.

Finding posted inline

🟡 Nitstatusline-tee.sh:834: mkdir "$spool" 2>/dev/null || return 0 isn't idempotent the way the sibling directory-creation calls in this same file are (mkdir -p "$dir" at lines 240 and 831). Two renders racing at the very first cold start on a machine (or right after upgrading, with several sessions already open) can have the mkdir loser hit EEXIST and bail via return 0 before writing its spool record — silently dropping that one refresh. Self-heals on the next refresh and is well inside the 10-minute staleness budget, so this is low-impact, but mkdir -p closes the gap with no downside and matches the established pattern. Suggested fix posted as an inline suggestion.

What held up well

  • The core atomicity argument (file disjointness for the spool records, torn-record drop via fromjson failure, and the unchanged atomic temp-then-rename in tee_snapshot) is sound and matches the REVIEW.md atomicity check for multi-file writes.
  • The drain election (own lock, re-read-stamp-under-lock, bounded steal) correctly avoids the herd/self-eviction problems the PR description calls out, and doesn't regress the pre-existing "window-bearing writer proceeds through a lock it couldn't take" semantics in tee_snapshot.
  • The shard-name sanitization (^[A-Za-z0-9._-]{1,64}$, no leading dot, else misc) is applied consistently and is covered by the hostile-input test case (traversal, embedded quote, 200-char id, leading dot, embedded space).
  • _RLG_BODY_JQ being shared between the live probe and the drain is a good move — it removes the risk of the two projections drifting.
  • Reader-contract.md's description of the spool inventory, drain cadence, and .tee-disabled marker matches the implementation.

Not independently verified

The Bash tools available to this review lane don't permit executing the test suite or shellcheck directly in this sandbox, so the PR description's PASS=96 FAIL=0 result and the xtrace zero-fork claim are author-claimed and not independently confirmed here — reviewed via static reading of statusline-tee.sh and statusline-tee.test.sh only.
· branch

Comment thread plugins/rate-limit-guard/scripts/statusline-tee.sh
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 1m 5s —— View job


Security review — /review:security-review

Task list

  • Gather context (PR diff, HEAD SHA 4390333)
  • Invoke /review:security-review skill and follow its instructions exactly
  • Post findings

Skip gate hit — no new review performed.

The current HEAD (4390333) already has a successful security review that still applies (skip-gate condition 3). Diffing the previously-reviewed SHA (aad6de8) against the current HEAD (aad6de8..4390333) shows this commit is only a merge that forwards main plus a changelog-parity fix:

  • plugins/rate-limit-guard/CHANGELOG.md — one blank-line removal, no content change
  • plugins/rate-limit-guard/hooks/hook-utils.sh — changed, but only because it was pulled in from main (fa762fb); this file is not part of this PR's diff against origin/main (git diff origin/main...HEAD confirms it's absent from the PR's changed-file set)
  • reference/reader-contract.md, scripts/statusline-tee.sh, scripts/statusline-tee.test.sh, .claude-plugin/plugin.jsonbyte-identical between aad6de8 and 4390333

So the PR's actual security-relevant surface (the spool/drain logic in statusline-tee.sh, the shard-key validation, the drain lock, and the reader-contract doc) is unchanged since the last full review at aad6de8, which found no CRITICAL or IMPORTANT issues and one SUGGESTION (spool file permissions, already posted inline and still open).

No new findings to report.
· branch: perf/statusline-tee-spool

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 2m 8s —— View job


Code review — /review:code-review

Task list

  • Gather context (PR diff via gh pr diff, commit history since last lane review)
  • Check skip gate
  • Confirm no code changes since last lane review
  • Post findings

Skip gate: no new review surface since the last pass from this lane

This lane already reviewed this PR's code at commit aad6de8 (comment posted 2026-08-12T21:49:19Z), covering statusline-tee.sh, statusline-tee.test.sh, and reader-contract.md in full, and flagged one nit (mkdir "$spool" vs mkdir -p "$spool" at statusline-tee.sh:834).

Diffing aad6de8..e8cd2d0 (the two commits added since that review — 4390333 merge-forward from main, and e8cd2d0 restoring a changelog heading) against this PR's scope:

  • plugins/rate-limit-guard/scripts/statusline-tee.shunchanged
  • plugins/rate-limit-guard/scripts/statusline-tee.test.shunchanged
  • plugins/rate-limit-guard/reference/reader-contract.mdunchanged
  • plugins/rate-limit-guard/.claude-plugin/plugin.jsonunchanged (version was already 0.7.0 at aad6de8)
  • plugins/rate-limit-guard/CHANGELOG.md — one docs-only change: restoring the ## [0.6.3] heading/entry that a merge-forward from main had dropped, so the changelog stays in sync with the merged hook-utils.sh fix. No new claims, no code.

Everything else in aad6de8..e8cd2d0 touches unrelated plugins' hook-utils.sh/CHANGELOG.md/plugin.json pulled in by the merge-forward — already on main, outside this PR's diff (gh pr diff confirms the net diff against origin/main is still exactly these 5 rate-limit-guard files).

Per the skip gate ("this head already has a successful review from this lane that still applies"), there is no new code for this lane to review. The prior review's finding and "what held up well" notes still stand; no new findings to add.
· branch: perf/statusline-tee-spool

@cursor
cursor Bot force-pushed the perf/statusline-tee-spool branch from e8cd2d0 to dba094b Compare August 12, 2026 22:34
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 1m 37s —— View job


Security review — /review:security-review

Task list

  • Gather context (PR diff at HEAD dba094b via git diff origin/main...HEAD, prior review history on this PR)
  • Invoke /review:security-review skill and follow its instructions exactly
  • Post findings

Skip gate hit (condition 3) — no new review performed.

git diff origin/main...HEAD at the current head (dba094b) touches the same 5 files with the same +605/-18 shape this lane already reviewed in full earlier on this PR. The intermediate commits from that prior review (aad6de8, 4390333, e8cd2d0) are no longer reachable in this checkout — consistent with a rebase/squash that produced today's single-commit head — so I couldn't diff SHA-to-SHA. Instead I diffed content directly:

  • statusline-tee.sh — byte-identical THE SPOOL section (_rlg_shard_name, acquire_drain_lock, _rlg_drain, _rlg_spool_dispatch), same line numbers as the prior review: mkdir "$spool" still at line 834, the per-session record write still at line 856, the max(.e) selection still at line 771.
  • reference/reader-contract.md — same spool/drain/.tee-disabled documentation as previously reviewed.
  • .claude-plugin/plugin.json, CHANGELOG.md, statusline-tee.test.sh — version bump, changelog, and tests only; no independent security surface.

So the PR's actual security-relevant surface (shard-key validation, the drain lock, the atomic-write/torn-record handling, the enablement gate) is unchanged from the state this lane already reviewed, which found no CRITICAL or IMPORTANT issues and one open SUGGESTION (spool file permissions, posted inline on lines 826–856 — still unaddressed).

Two other open items from other reviewers on this same unchanged code, for completeness (not re-litigated here since this lane's scope is security only and the skip gate applies):

No new findings from this pass.
· branch: perf/statusline-tee-spool

cursoragent and others added 2 commits August 12, 2026 22:44
…cadence (0.7.0)

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…iene gate

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor
cursor Bot force-pushed the perf/statusline-tee-spool branch from 39dd89e to c2a4809 Compare August 12, 2026 22:44
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 1m 11s —— View job


Security review — /review:security-review

Task list

  • Gather context (PR diff at HEAD c2a4809 via git diff origin/main...HEAD, prior review history on this PR)
  • Invoke /review:security-review skill and follow its instructions exactly
  • Post findings

Skip gate hit (condition 2 + 3) — no new review performed.

Diffing the previously-reviewed head (dba094b, reviewed 2026-08-12T22:34:41Z) against the current head (c2a4809):

  • statusline-tee.shbyte-identical to the previously-reviewed version. The THE SPOOL section (_rlg_shard_name, acquire_drain_lock, _rlg_drain, _rlg_spool_dispatch), the shard-key validation, the drain lock, and the atomic-write/torn-record handling are unchanged.
  • statusline-tee.test.shunchanged.
  • reference/reader-contract.md, CHANGELOG.md — the only files touched by c2a4809 ("format CHANGELOG and reader-contract for hygiene gate"). This is a markdown-formatting-only pass (table alignment, *emphasis*_emphasis_, JSON code-block re-indentation) with no change to any documented guarantee, threat-relevant claim, or code path — no new security-relevant surface.
  • .claude-plugin/plugin.json — unchanged from dba094b.

So the PR's actual security-relevant surface (shard-key validation, the drain lock, the atomic-write/torn-record handling, the enablement gate) remains exactly what this lane already reviewed at dba094b: no CRITICAL or IMPORTANT issues, one open SUGGESTION (spool file permissions, still unaddressed).

No new findings to report.
· branch: perf/statusline-tee-spool

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cursor[bot]'s task in 48s —— View job


Code review — /review:code-review

Task list

  • Gather context (PR diff via git diff origin/main...HEAD, commit history since last lane review)
  • Check skip gate against prior lane reviews on this PR
  • Confirm no new review surface since the last full pass from this lane
  • Post findings

Skip gate hit — no new review surface since the last full pass from this lane

This lane already reviewed this PR's code in full (comment posted 2026-08-12T21:49:19Z, covering statusline-tee.sh, statusline-tee.test.sh, and reader-contract.md), flagging one nit: mkdir "$spool" vs mkdir -p "$spool" at statusline-tee.sh:834, still open. Two subsequent lane passes on this PR (e8cd2d0, then again after a rebase) each reconfirmed no code changes since.

Diffing the last-reviewed head (c2a4809) against the current head (72210ec48f21e162db21ab56ac8b8aee882b8db0):

  • plugins/rate-limit-guard/CHANGELOG.md — the only file touched. Six occurrences of _emphasis_ in pre-existing 0.5.x/0.6.x changelog entries (unrelated to this PR's own 0.7.0 entry) were reformatted to *emphasis*, purely a Markdown emphasis-style fix (matches the prior commit's stated goal, "fix MD049 emphasis style"). No wording, claim, or code changed.
  • plugins/rate-limit-guard/scripts/statusline-tee.shunchanged
  • plugins/rate-limit-guard/scripts/statusline-tee.test.shunchanged
  • plugins/rate-limit-guard/reference/reader-contract.mdunchanged
  • plugins/rate-limit-guard/.claude-plugin/plugin.jsonunchanged

Per the skip gate ("this head already has a successful review from this lane that still applies" / "change is trivial/automated with no meaningful review surface"), there is no new code-review surface at this head. The prior finding stands; no new findings to add.
· branch: perf/statusline-tee-spool

@kyle-sexton
kyle-sexton merged commit b87717f into main Aug 12, 2026
38 checks passed
@kyle-sexton
kyle-sexton deleted the perf/statusline-tee-spool branch August 12, 2026 22:59
kyle-sexton added a commit that referenced this pull request Aug 14, 2026
… contract suite

Address all five PR review findings:

- Timer reads no longer fork: now_ms assigns via printf -v instead of a
  $(command substitution), which on MSYS added roughly a spawn floor to
  every sample (measured same-window on the repo tee: old instrument
  median 1434 ms vs new 510 ms). README carries an instrument note: the
  recorded #2521 absolutes are instrument-inclusive; the delta stands.
- Missing EPOCHREALTIME (bash < 5.0) is now a loud refusal with rationale
  instead of a set -u unbound-variable abort; README reconciles this
  hard floor with the tee's own graceful 3.2+ degradation.
- A failing render aborts the lane (bench-idle exits, bench-load marks
  and discards the run) instead of being timed as a plausible sample.
- The load lane's pad-to-one-second arithmetic is computed properly in
  pace_sleep_arg: 0 ms spent now sleeps 1.000 s, not 0.1 s.
- New co-located bench.test.sh contract smoke suite: unit-tests the lib
  helpers, runs each lane once with tiny parameters against the repo tee
  under an isolated HOME, and asserts the failure-abort paths — shape
  and behaviour only, never timing. scripts/affected-tests.sh --explain
  now maps every changed path (the P1 finding); exec bits set on all
  five scripts for the hygiene exec-bit gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aac8xjCjMxFsXGHCXKHY4W
kyle-sexton added a commit that referenced this pull request Aug 14, 2026
…s (0.7.4) (#2583)

## Summary

PR #2521's headline render-path measurement — `render.sh` alone **234.4
ms** vs **1047.1 ms** behind the pre-#2521 tee (Windows/MSYS, n=9,
same-window) — was produced by a benchmark harness that lived only in an
untracked local scratch directory. The merged perf claim was
unreproducible, and nothing could catch a regression that quietly
reintroduced the render-path cost. This PR commits the harness.

- **`bench/lib-bench.sh`** — shared helpers: the spawn-floor control
(median of 11 bare `bash -c exit` spawns, bracketing every timed section
— on MSYS the process-creation floor dominates every number, so a run
whose floor moved is discarded), the canonical statusline payload
fixture, `now_ms`/`median`.
- **`bench/bench-idle.sh`** — the lane that produced the headline
numbers: N sequential renders, floor before/after, median + mean + raw
samples.
- **`bench/bench-load.sh`** — the concurrency lane: N virtual sessions
rendering once a second for M seconds, the shape that stresses the
spool/drain election.
- **`bench/trace-probe.sh`** — xtrace of a non-elected render, printing
everything executed before passthrough: the check that the render path
stays fork-free, which is the property #2521 exists to protect.
- **`bench/README.md`** — records what #2521 measured, on what platform,
with what discipline, and how to re-run each lane (including isolating a
run from the machine's live `~/.claude/rate-limit-guard/` contract
file).

Plugin `0.7.3 → 0.7.4` with a changelog entry, per the
shipped-contents-change convention.

## Adaptation from the scratch originals

- `STATUSLINE_ENTRY` no longer defaults to a machine-local
`~/.claude/statusline/entrypoint.sh`; it defaults to this repo's
`scripts/statusline-tee.sh` in standalone mode, resolved relative to the
bench dir — runnable from a clean checkout. The env override is
documented for measuring a real machine entrypoint.
- `trace-probe.sh` defaults its tee argument to the repo copy the same
way (it already isolated itself under a throwaway `HOME`).
- `# shellcheck disable=SC2034` on the payload fixture (consumed by the
sourcing scripts), matching the hook-utils precedent.
- Everything else is byte-faithful to what produced the #2521 numbers.
Verified against the tee at head: spool path, `.last-drain` stamp,
`RLG_TEE_DRAIN_INTERVAL` (default 30), and the `{"e":…,"p":…}` record
shape all still match.

Three scratch files were **not** brought over: `gates.sh` (throwaway
wrapper around repo CI gates, hardcoded to a dead worktree path),
`pr-body.md` (byte-identical to #2521's merged body), `gates.log`
(empty).

## CI stance

Deliberately no CI wiring: a wall-clock benchmark on shared runners is
noise, not a gate. None of these files use the `*.test.sh` suffix that
`scripts/run-plugin-tests.sh` and the CI test lanes discover, so nothing
new runs or gates in CI beyond the standard shell-lint gates. The tee's
behavioural coverage remains `scripts/statusline-tee.test.sh`.

## Verification

- Smoke-ran from the clean worktree: `bench-idle.sh 3` under an isolated
`HOME`, and `trace-probe.sh` (pre-passthrough trace shows builtin-only
work).
- `shellcheck -x --rcfile=.shellcheckrc`, `shfmt -d`,
`scripts/check-shell-portability.sh --paths` on all four scripts: clean.
- `markdownlint-cli2`, `typos`, `editorconfig-checker` on changed files:
clean.
- `scripts/check-changelog-parity.sh` `--check` / `--check-order` /
`--check-bump origin/main` / `--check-preserved origin/main`: pass.
- `scripts/validate-plugins.sh`: all manifests + catalog pass.
- All 15 suites `scripts/affected-tests.sh origin/main` selected: pass.
- rate-limit-guard's own suites (`statusline-tee.test.sh` 96,
`statusline-shim.test.sh` 36, `record-rate-limit-stop.test.sh` 19): all
pass.

## Related

Closes #2582

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01Aac8xjCjMxFsXGHCXKHY4W

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants