Skip to content

feat(tui): per-path concurrency limit + /health observability (PR-B)#139

Merged
dtzp555-max merged 1 commit into
mainfrom
feat/tui-concurrency-observability-pr-b
Jun 10, 2026
Merged

feat(tui): per-path concurrency limit + /health observability (PR-B)#139
dtzp555-max merged 1 commit into
mainfrom
feat/tui-concurrency-observability-pr-b

Conversation

@dtzp555-max

Copy link
Copy Markdown
Owner

Summary

PR-B — TUI-path concurrency limit + /health observability (audit findings C-4/C-5).

  • C-4 OCP_TUI_MAX_CONCURRENT (default 2) bounds concurrent interactive claude boots via a queuing semaphore (lib/tui/semaphore.mjs). The slot is released in a finally, so PR-A's honesty-gate throws (tui_wallclock_truncated / tui_upstream_error) and runTuiTurn's throws (tui_spawn_failed / tui_paste_not_landed) never leak a slot. Bounded wait-queue → tui_queue_full (503) on overflow. Independent of the global MAX_CONCURRENT (8) — a TUI turn is a per-request cold-boot of tmux+claude + up to 120s wallclock, far heavier than a stream-json spawn.
  • C-5 additive /health tui block (enabled / entrypointMode / lastEntrypoint / entrypointMismatches / inflight / maxConcurrent) so an operator can poll for the silent sdk-cli metered-pool drift (the audit's top risk) instead of grepping journald. Every pre-existing /health field is unchanged.

ALIGNMENT

Class B. cli.js does not perform this operation (TUI is an OCP-owned subscription-pool bridge). /health is a grandfathered B.2 endpoint (ADR 0006); the additive tui block is authorized by the ADR 0007 PR-B amendment under ALIGNMENT.md's grandfather provision ("a behaviour-preserving refactor PR or its own ADR") — every pre-existing field is byte-identical, only the new tui key is appended (behaviour-preserving for existing consumers). No Class A path / .github/workflows/alignment.yml / models.json touched.

Tests

npm test235 passed, 0 failed (was 224; +11: semaphore bounding/serialize/queue-full/slot-release-on-throw, mismatch-counter semantics incl. null-and-auto-mode handling, /health tui block shape).

Independent review (Iron Rule 10)

Fresh-context reviewer APPROVED: ran npm test (235/0); diffed old-vs-new /health to confirm the change is additive/behaviour-preserving; ruled the ADR-0007-amendment authorization valid (not a new-ADR case — no new endpoint or method; the grandfather provision's "its own ADR" path is satisfied, and the additive change independently qualifies as behaviour-preserving); independently probed the semaphore (limit=1 serializes overlapping calls; 5 sequential throws → inflight===0, slot reusable); confirmed no Class A / workflow / models.json touched. Author (dtzp555) did not self-approve.

Non-blocking note from review: ADR 0006 is still "Proposed" status (its grandfather text is operative regardless); maintainer may reconcile separately — out of scope for this PR.

🤖 Generated with Claude Code

Two P1 audit fixes for the TUI subscription-pool bridge (ADR 0007). The
default path (CLAUDE_TUI_MODE unset) is unchanged except the additive
/health `tui` block (enabled:false when off).

C-4 — TUI path had NO concurrency bound. The global MAX_CONCURRENT gate
lives in spawnClaudeProcess (the -p/stream-json path); callClaudeTui never
calls it — it calls runTuiTurn, which cold-boots a full interactive claude
in tmux. So N concurrent TUI requests spawned N simultaneous cold boots (a
family burst of 5 on a Pi 4 = OOM risk + subscription rate-limit pressure).
Adds an independent in-process limiter (lib/tui/semaphore.mjs, TuiSemaphore)
gating callClaudeTui: OCP_TUI_MAX_CONCURRENT (default 2 — a TUI turn is heavy:
per-request cold-boot + up to 120s wallclock). Queues rather than rejects
(mirrors MAX_CONCURRENT intent), with a bounded wait queue (default 32x the
limit) → tui_queue_full (503) on overflow rather than unbounded growth. The
slot releases in a finally, so PR-A's honesty-gate throws / timeouts / paste
failures never leak a slot.

C-5 — no operator-visible TUI drift surface. The tui_entrypoint_mismatch
warning only reached journald; after the 6/15 flip a silent sdk-cli drift
(the documented top risk) would drain metered credits invisibly. Adds an
additive `tui` block to /health: { enabled, entrypointMode, lastEntrypoint,
entrypointMismatches, inflight, queued, maxConcurrent }. lastEntrypoint /
entrypointMismatches are recorded in callClaudeTui (same mismatch branch the
journald warning covers); inflight/queued come from the C-4 semaphore.

ALIGNMENT (Class B): cli.js does NOT perform this operation — both the TUI
path and /health are OCP-owned, so no cli.js citation applies. /health is a
grandfathered B.2 endpoint (ADR 0006, frozen at v3.16.4). The response-shape
change is authorized by the ADR 0007 PR-B amendment added in this commit and
is behaviour-preserving: the `tui` block is NEW fields only — no existing
/health field is changed, renamed, removed, or re-typed, and no existing
semantics change, so existing consumers (dashboard, ocp-connect, monitoring)
are unaffected. Per ALIGNMENT.md's grandfather provision, an additive
behaviour-preserving change to a grandfathered B.2 endpoint is authorized by
an ADR; ADR 0007 is the authority for the TUI observability surface. No
Class A forwarding path, no alignment.yml, no models.json touched — alignment
blacklist is unaffected (zero new network tokens).

Tests: 11 new (lib/tui/semaphore.mjs is importable, so the semaphore + the
two pure /health helpers are tested directly): limit=1 serializes two
overlapping calls; limit=2 runs two + queues the third; slot released on
throw; bounded queue → tui_queue_full; mismatch counter increments on
cli→other drift; auto mode never counts a mismatch; /health tui block shape
+ live inflight/queued. npm test: 235 passed, 0 failed (was 224).

Co-Authored-By: Claude <claude-opus> <noreply@anthropic.com>
@dtzp555-max dtzp555-max merged commit 3322d7b into main Jun 10, 2026
5 checks passed
@dtzp555-max dtzp555-max deleted the feat/tui-concurrency-observability-pr-b branch June 10, 2026 11:54
dtzp555-max added a commit that referenced this pull request Jun 10, 2026
… (PR-A/B/C, #137-139) (#140)

Bump 3.19.0 → 3.20.0 + CHANGELOG. Aggregates three already-reviewed, already-merged PRs:
- #137 (PR-A) TUI honesty/cache correctness
- #139 (PR-B) TUI concurrency limit + /health observability
- #138 (PR-C) 6/15 canary + flip/rollback runbooks + setup auth-probe guard

README env-var / endpoint tables were updated in the respective feature PRs.

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude <claude-fable-5> <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