Skip to content

Add bounded tmux user-option persistence and fix nested inventory#167

Merged
ictechgy merged 93 commits into
mainfrom
feature/tmux-user-options-omx-ownership
Jul 20, 2026
Merged

Add bounded tmux user-option persistence and fix nested inventory#167
ictechgy merged 93 commits into
mainfrom
feature/tmux-user-options-omx-ownership

Conversation

@ictechgy

Copy link
Copy Markdown
Owner

tmux user-option persistence, lifecycle/generation safety, and nested-session inventory repair

Status: Draft PR — ready for review, not merged. No merge authorization has been given; this branch stops at review-ready.

Problem & root cause

  • set-option was previously an unconditional no-op, so tmux-compatible tooling that persists @user-options silently lost state; documentation overstated tmux compatibility relative to actual behavior.
  • Compatibility-store cleanup on pane/session kill was not guarded against pane-ID reuse, so a recycled pane generation could delete another identity's entries; a lifecycle journal file lock inherited across fork() could be held past its owner's lifetime.
  • Nested-session inventory regression: a nested named child launched without --tmux (after a wrapper stripped the capability environment) was stored without parent provenance and therefore appeared as a root in default ls. Root cause: an over-broad child-tmux-mode gate on both the client fallback provenance path and server parent acceptance suppressed legitimately verified provenance. The gate was never a trust boundary — every verification predicate (self-provided-socket match, strict %digits pane format, capability/explicit precedence, parent liveness) is retained; only the erroneous gate is removed.

Implementation

Immutable-ID tmux user-option persistence

  • Stateful set-option/set for a bounded @name subset, read via show-options/show-option/show, with a strict grammar ([-pqu] [-t target] [--] @option [value]; -q absent-option success semantics; -- ends parsing; -t separate or attached, never clustered).
  • Values key off immutable UUIDs (root session by default, pane with -p), so they survive session renames. Strict name charset/length and value size limits; C0/C1/DEL controls and a published Unicode Cf/bidi/zero-width/variation-selector denylist rejected; bounded per-identity, total-identity, total-entry, and store-size limits.
  • Non-user-option set-option calls and set-window-option/setw retain legacy accepted no-op behavior.

Lifecycle & generation safety

  • Kill cleanup is generation-guarded: removal requires the captured immutable identity to match the stored row, so reused pane IDs can never delete another generation's entries; failed kills preserve the store; live-identity reconciliation removes naturally exited or reused identities and mops up any missed best-effort cleanup.
  • Journal flock RAII guard now explicitly unlocks on Drop (SAFETY-commented), defeating fork-inherited lock extension.
  • Lifecycle snapshots fail closed before tmux lifecycle kills.

Exact OMX interoperability & truthful docs

  • README.md, README.ko.md, and docs/public-contract.md now document set-option as partial (not full tmux option support) with the exact accepted grammar, identity model, limits, and denylist; list-sessions format tokens like #{@omx_instance_id} read root-session values only and never leak pane/window values. Explicitly stated non-goals: no built-in, global, server, window, or inheritance option semantics.

Nested-session inventory regression repair

  • Removes only the child-tmux-mode gate from client fallback provenance discovery and server parent acceptance. Self-socket matching, pane-format validation, capability/explicit-parent precedence, and server-side parent liveness validation all remain; no name/cwd/process heuristics introduced; already-persisted parentless rows are intentionally not backfilled (fix applies at new-session time only). A child under real external tmux still stays a root (asserted negative control).

Impact

  • Users: tmux-compatible tools can persist and read @user-options that survive renames; default ls again shows only true root sessions, with descendants reachable via --children/--all; no behavior change for already-persisted records or raw attach.
  • Developers: public contract and READMEs are truthful about the partial support surface; cleanup paths are provably generation-safe; regression-first tests lock every repaired boundary.

Test matrix

Gate Result
Focused regression tests (new + existing provenance/user-option/lifecycle) ✅ Pass
Full locked test suite (cargo test --locked) ✅ Pass
cargo fmt -- --check ✅ Pass
cargo check --all-targets ✅ Pass (0 warnings)
cargo clippy --locked --all-targets -- -D warnings ✅ Pass
cargo build --release --locked ✅ Pass
cargo audit ✅ 0 vulnerabilities; 1 allowlisted informational warning (see below)
Contract validators (manifest self-test + validity, 12 manifest-listed doc examples, drift check, URL policy) ✅ All pass
Isolated live smoke (fresh 0700 HOME/runtime, dedicated daemon) ✅ Pass — nested child hidden by default, exact parent provenance under --all, --children exposure, external-tmux negative control, clean shutdown

The isolated smoke additionally verified the pre-existing production inventory was byte-for-byte unchanged before and after (no values reproduced here by design).

Security & privacy constraints

  • No trust boundary weakened: parent provenance is accepted only with an exact self-provided tmux socket match and validated pane format; server retains liveness validation; no process-name/cwd heuristics.
  • No new dependencies (Cargo.toml/Cargo.lock unchanged across the range, verified empirically).
  • Strict input validation on option names/values, including a Unicode control/format-character denylist and hard size caps, fail-closed lifecycle snapshots.
  • This PR body and all stored evidence deliberately exclude local paths, usernames, live session identifiers, and production data.

Known non-blocking audit note

cargo audit reports one informational "unsound" advisory (RUSTSEC-2026-0190) in a transitive dependency. It is explicitly allowlisted, reports zero vulnerabilities, and is not claimed to be risk-free — it is tracked as informational and does not block this PR.

Review evidence

  • Independent code-reviewer final gate at the exact reviewed head: APPROVE — CRITICAL 0 · HIGH 0 · MEDIUM 0 · LOW 0 (1 informational, non-actionable), commit verified byte-exact, spec compliance and all eight review invariants independently re-verified in code.
  • Independent architect devil's-advocate review: CLEAR / accept — minimal correctly-scoped change, no security boundary weakened, no dependency additions confirmed.

Draft PR: ready for review; merge intentionally withheld pending explicit authorization.

ictechgy added 30 commits July 17, 2026 00:02
This reverts commit 1933038, reversing
changes made to ce75596.
ictechgy and others added 27 commits July 17, 2026 19:22
lterm new --detach로 tmux 플래그 없이 중첩 실행된 자식이 검증된
self-lterm 부모 provenance를 잃는 문제(G012)를 수정한다.

- client: current_verified_lterm_tmux_parent에서 tmux 불리언 파라미터와
  조기 false 반환을 제거 (소켓 pane 우선순위·real-tmux 검증은 유지)
- server: parent_request의 동일한 !tmux 게이트를 제거 (capability 조합
  금지, pane id 형식, 부모 생존 검증은 유지)
- test: 중첩 provenance 테스트에 tmux 플래그 없는 자식 케이스와
  ls --children --json 노출 계약 검증을 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
암묵(env) 복구된 tmux 부모는 tmux-parent 프로토콜 검사 실패 시 하드 실패
대신 root 세션으로 안전 강등한다(프라이버시-안전 경고만 출력). 명시 부모
엄격성, capability 부모 우선순위, 중첩 provenance, 서버측 검증은 불변.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the shell-and-sleep PTY fixture with a direct cat leader and validate retained process-group identity through the production gate before exercising the forced waitid fallback close race.
@ictechgy
ictechgy marked this pull request as ready for review July 20, 2026 19:44
@ictechgy
ictechgy merged commit 74ac94a into main Jul 20, 2026
9 checks passed
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