fix: normalize relative paths and add integration tests#6
Merged
Conversation
resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 20, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 20, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 21, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 24, 2026
The single-file `input.rs` grew to ~4750 lines and combined top-level dispatch, list/editor/prelude/confirm-delete stage handlers, save-flow plumbing, mouse/geometry helpers, and a large test suite. Split it into `input/` as a directory module: - `input/mod.rs` — thin top-level dispatcher (`handle_key`, `handle_mouse`), `InputOutcome`, re-exports. - `input/list.rs` — list-stage key/modal handling. - `input/editor.rs` — editor-stage key/modal handling, tab dispatch, agent-allow toggles, agent-default selection. - `input/save.rs` — `begin_editor_save`, `commit_editor_save`, save-flow helpers (`build_workspace_edit`, confirm-save line builders, etc.). - `input/prelude.rs` — create-workspace wizard. - `input/mouse.rs` — mouse events, seam drag, list hit-test, file-browser URL click. Tests travel with the behavior they exercise. No runtime behavior change — key bindings, mouse behavior, save semantics, and dispatch order are all byte-identical. Addresses finding #6 of the PR #166 current-branch review. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Claude <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 24, 2026
`render.rs` grew to ~2350 lines and combined the top-level stage switch, list chrome, editor tabs, modal dispatcher, footer composition, and visual-regression tests. Split into `render/` as a directory module: - `render/mod.rs` — stage-switch entry point (`render`), header renderer, shared geometry helpers, cross-cutting re-exports. - `render/list.rs` — list-stage body, toast, details/sentinel right-pane renderers. - `render/editor.rs` — editor-stage body, tab-bar, per-tab renderers. - `render/modal.rs` — modal dispatcher (`render_modal`), `modal_outer_rect` shared geometry helper. - `render/footer.rs` — `FooterItem`, `render_footer`. Tests travel with the behavior they exercise. No visual or layout change — the operator sees pixel-identical output. Addresses finding #6 of the PR #166 current-branch review. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Claude <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
Apr 24, 2026
…odules `file_browser.rs` grew to ~1800 lines and combined filesystem scanning, sandbox policy, git-repo detection, git URL resolution, keyboard navigation, a git-prompt state machine, mouse URL hit-test, rendering, and a large test suite. Split into `file_browser/` as a directory module: - `file_browser/mod.rs` — module doc, shared palette, module declarations, cross-module re-exports. - `file_browser/state.rs` — `FileBrowserState`, `FolderEntry`, sandbox helpers (`is_within_root`, `canonicalize_or_self`), listing helpers (`load_entries`, `has_git_dir`, `is_excluded`), navigation (`set_cwd`, `reload`, `navigate_up`). - `file_browser/input.rs` — keyboard/mouse event handling (`handle_key`, `handle_enter`, `commit_or_reject`, `maybe_open_url_on_click`). - `file_browser/render.rs` — `render`, row styling. - `file_browser/git_prompt.rs` — `GitPromptFocus`, `handle_git_prompt_key`, `render_git_prompt`, `resolve_git_url`. Tests travel with the behavior they exercise. No behavior change — keyboard behavior, sandbox rules, mouse URL opening, and rendering are all byte-identical. Addresses finding #6 of the PR #166 current-branch review. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com>
donbeave
added a commit
that referenced
this pull request
Apr 24, 2026
The `input/mod.rs` `#[cfg(test)] mod tests` block held ~1800 lines of test cases covering every stage. That concentration forced future maintainers to navigate a large mixed-responsibility file and surfaced in static analysis as a cluster of duplicate-binding warnings localized to one place. Disperse the tests so each submodule owns the tests for the behavior it owns: - list-stage tests -> input/list.rs - editor-stage tests -> input/editor.rs - save-flow tests -> input/save.rs - create-wizard tests -> input/prelude.rs - mouse tests stay in input/mouse.rs input/mod.rs retains only the genuine cross-flow test that drives multiple stages in one case (create-mode rename + save). Shared helpers `key()` and `mount()` are lifted to a `test_support` sibling module since they show up in 3+ submodules; submodule- local helpers (setup_with_workspace, press_s, etc.) stay co- located with their tests. No behavior change. Test count unchanged (829 -> 829). Addresses finding #6 of the second-pass PR #166 review. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
- Move 9 TODO items from monolithic TODO.md into separate files in todo/ - Each file is a self-contained design doc with problem, options, and related source files for easy agent handoff - Mark resolved security findings (#3, #4, #6, #7) in SECURITY_REVIEW_FINDINGS.md - Update PROJECT_STRUCTURE.md with todo/ section and TESTING.md entry - TODO.md becomes an index pointing to todo/ files Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
donbeave
added a commit
that referenced
this pull request
May 7, 2026
…ts (#6) resolve_path now normalizes path components so `../sibling` becomes a clean absolute path instead of `/a/b/../sibling`. Also resolves relative `--src` in `config mount add` and adds integration tests that mirror the exact CLI scenarios (workspace add/edit with relative workdir and mounts). Updates AGENTS.md with branching policy requiring feature branches. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Claude <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
May 23, 2026
Trust-but-verify pass on the 15-item /code-review max-effort report that followed the parallel-agent capture commit. Splits cleanly from the in-flight env-config refactor by touching only the host-side session-inventory and snapshot-fanout paths plus the capsule socket layer; parallel-agent territory (main.rs, daemon.rs, session.rs, launch.rs, env_model.rs, derived_image.rs, entrypoint.sh) stays untouched. Findings addressed: * `src/console/manager/state.rs` — fan-out worker panics now surface through the existing `debug_log` path: `h.join()` failures are downcast to a string and re-routed as `Err(anyhow!)` so the slot is no longer dropped by `filter_map(|h| h.join().ok())`. Snapshot fan-out is also bounded by `SNAPSHOT_FANOUT_CHUNK = 8` so a host with dozens of active containers does not spawn dozens of OS threads per 500 ms refresh tick; each chunk's wall-clock cost is still bounded by the slowest fetch in that chunk. The fan-out body moves into a free `fetch_snapshots_parallel` helper so `refresh_instances` stays under the clippy line-count gate. * `src/runtime/attach.rs` — `JACKIN_STATUS_CMD` now gates on `test -S /jackin/run/jackin.sock` so the early-bring-up window (between container start and the daemon binding its socket, plus any pre-`setup-once` time) does not leak operator-visible stderr from a binary that exists but cannot serve yet. `test -S` exits silently with status 1 if the socket is absent; `||` short- circuits at the first failure only — no `|| true` masking the second command's errors once the socket exists. `parse_jackin_sessions` drops the strict `len() != expected` equality in favour of `take(expected)` so trailing footer lines or labels that `Display`-emit a non-`[` continuation line no longer flip the parse to Unavailable; the count check is now a lower-bound (`< expected`), which still catches real format drift but tolerates harmless decoration. The header search lifts a shared `parse_session_count` helper used by both `inspect_agent_sessions` here and `isolation::finalize::has_jackin_sessions`, replacing the duplicate parser that was warned about in finding #3. * `src/isolation/finalize.rs` — `parse_session_count` is now `runtime::attach::parse_session_count`; the local copy is gone. One header parser, one definition of malformed, no silent divergence on edge cases. * `crates/jackin-capsule/src/socket.rs` — accept-loop cap-rejection log now fires exactly once on the saturation transition + once on the recovery transition, with per-drop messages demoted to `cdebug!` so a flood attacker (the exact threat `MAX_CONCURRENT_CLIENTS` defends against) cannot drown the compact-tier log. Per-backoff line also demoted to `cdebug!` — the accept-error clog above already names the failure, so the 1-line-per-failure compact-log invariant holds. `start_listener_at` splits behind a new `start_listener_at_with_limiter` test-only helper that returns the inner `Arc<Semaphore>`. The cap regression test now reads `limiter.available_permits()` directly instead of racing `rx.recv()` against a 300 ms wall-clock deadline — cap-sensitive, not timing-sensitive. Wall-clock `timeout()` windows widen to 2 s for the remaining positive assertions so a slow CI runner does not produce spurious failures. * `crates/jackin-capsule/src/protocol/attach.rs` — new `hello_env_count_over_cap_is_rejected_by_decoder_with_full_payload` variant supplies a fully-populated payload of `MAX_HELLO_ENV + 1` real entries so the per-entry boundary is verified after the read loop, not just at the count declaration. The earlier test only exercised the front-of-loop guard; a regression that moved the cap check below the per-entry loop would slip past it silently. Deferred (parallel-agent territory or out-of-scope for this pass): * `crates/jackin-capsule/src/session.rs` kitty single-pop vs N-push asymmetry (finding #6) and `focus_swap_reset_*` test-name overpromises (finding #12) — `session.rs` is mid-rebase by the parallel agent. * `crates/jackin-capsule/src/main.rs` `--focus` eprintln eaten by alt-screen swap (finding #8) — `main.rs` mid-rebase. * `src/runtime/launch.rs` `fake_docker_for_clean_attached_exit` fixture ordering (finding #14) — `launch.rs` mid-rebase under the env-config migration. Setup-once gating left untouched: `docker/runtime/entrypoint.sh` already gates on `/jackin/state/hooks/setup-once.done` (line 78, runs only if marker absent; line 88 writes the marker on success). The new `test -S` socket gate on the host-side status query is the orthogonal half of the "don't query during early bring-up" rule. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com>
donbeave
added a commit
that referenced
this pull request
May 23, 2026
Trust-but-verify pass on the 15-item /code-review max-effort report that followed the parallel-agent capture commit. Splits cleanly from the in-flight env-config refactor by touching only the host-side session-inventory and snapshot-fanout paths plus the capsule socket layer; parallel-agent territory (main.rs, daemon.rs, session.rs, launch.rs, env_model.rs, derived_image.rs, entrypoint.sh) stays untouched. Findings addressed: * `src/console/manager/state.rs` — fan-out worker panics now surface through the existing `debug_log` path: `h.join()` failures are downcast to a string and re-routed as `Err(anyhow!)` so the slot is no longer dropped by `filter_map(|h| h.join().ok())`. Snapshot fan-out is also bounded by `SNAPSHOT_FANOUT_CHUNK = 8` so a host with dozens of active containers does not spawn dozens of OS threads per 500 ms refresh tick; each chunk's wall-clock cost is still bounded by the slowest fetch in that chunk. The fan-out body moves into a free `fetch_snapshots_parallel` helper so `refresh_instances` stays under the clippy line-count gate. * `src/runtime/attach.rs` — `JACKIN_STATUS_CMD` now gates on `test -S /jackin/run/jackin.sock` so the early-bring-up window (between container start and the daemon binding its socket, plus any pre-`setup-once` time) does not leak operator-visible stderr from a binary that exists but cannot serve yet. `test -S` exits silently with status 1 if the socket is absent; `||` short- circuits at the first failure only — no `|| true` masking the second command's errors once the socket exists. `parse_jackin_sessions` drops the strict `len() != expected` equality in favour of `take(expected)` so trailing footer lines or labels that `Display`-emit a non-`[` continuation line no longer flip the parse to Unavailable; the count check is now a lower-bound (`< expected`), which still catches real format drift but tolerates harmless decoration. The header search lifts a shared `parse_session_count` helper used by both `inspect_agent_sessions` here and `isolation::finalize::has_jackin_sessions`, replacing the duplicate parser that was warned about in finding #3. * `src/isolation/finalize.rs` — `parse_session_count` is now `runtime::attach::parse_session_count`; the local copy is gone. One header parser, one definition of malformed, no silent divergence on edge cases. * `crates/jackin-capsule/src/socket.rs` — accept-loop cap-rejection log now fires exactly once on the saturation transition + once on the recovery transition, with per-drop messages demoted to `cdebug!` so a flood attacker (the exact threat `MAX_CONCURRENT_CLIENTS` defends against) cannot drown the compact-tier log. Per-backoff line also demoted to `cdebug!` — the accept-error clog above already names the failure, so the 1-line-per-failure compact-log invariant holds. `start_listener_at` splits behind a new `start_listener_at_with_limiter` test-only helper that returns the inner `Arc<Semaphore>`. The cap regression test now reads `limiter.available_permits()` directly instead of racing `rx.recv()` against a 300 ms wall-clock deadline — cap-sensitive, not timing-sensitive. Wall-clock `timeout()` windows widen to 2 s for the remaining positive assertions so a slow CI runner does not produce spurious failures. * `crates/jackin-capsule/src/protocol/attach.rs` — new `hello_env_count_over_cap_is_rejected_by_decoder_with_full_payload` variant supplies a fully-populated payload of `MAX_HELLO_ENV + 1` real entries so the per-entry boundary is verified after the read loop, not just at the count declaration. The earlier test only exercised the front-of-loop guard; a regression that moved the cap check below the per-entry loop would slip past it silently. Deferred (parallel-agent territory or out-of-scope for this pass): * `crates/jackin-capsule/src/session.rs` kitty single-pop vs N-push asymmetry (finding #6) and `focus_swap_reset_*` test-name overpromises (finding #12) — `session.rs` is mid-rebase by the parallel agent. * `crates/jackin-capsule/src/main.rs` `--focus` eprintln eaten by alt-screen swap (finding #8) — `main.rs` mid-rebase. * `src/runtime/launch.rs` `fake_docker_for_clean_attached_exit` fixture ordering (finding #14) — `launch.rs` mid-rebase under the env-config migration. Setup-once gating left untouched: `docker/runtime/entrypoint.sh` already gates on `/jackin/state/hooks/setup-once.done` (line 78, runs only if marker absent; line 88 writes the marker on success). The new `test -S` socket gate on the host-side status query is the orthogonal half of the "don't query during early bring-up" rule. Co-authored-by: Codex <codex@openai.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com>
donbeave
added a commit
that referenced
this pull request
May 23, 2026
Trust-but-verify pass on the 15-item /code-review max-effort report that followed the parallel-agent capture commit. Splits cleanly from the in-flight env-config refactor by touching only the host-side session-inventory and snapshot-fanout paths plus the capsule socket layer; parallel-agent territory (main.rs, daemon.rs, session.rs, launch.rs, env_model.rs, derived_image.rs, entrypoint.sh) stays untouched. Findings addressed: * `src/console/manager/state.rs` — fan-out worker panics now surface through the existing `debug_log` path: `h.join()` failures are downcast to a string and re-routed as `Err(anyhow!)` so the slot is no longer dropped by `filter_map(|h| h.join().ok())`. Snapshot fan-out is also bounded by `SNAPSHOT_FANOUT_CHUNK = 8` so a host with dozens of active containers does not spawn dozens of OS threads per 500 ms refresh tick; each chunk's wall-clock cost is still bounded by the slowest fetch in that chunk. The fan-out body moves into a free `fetch_snapshots_parallel` helper so `refresh_instances` stays under the clippy line-count gate. * `src/runtime/attach.rs` — `JACKIN_STATUS_CMD` now gates on `test -S /jackin/run/jackin.sock` so the early-bring-up window (between container start and the daemon binding its socket, plus any pre-`setup-once` time) does not leak operator-visible stderr from a binary that exists but cannot serve yet. `test -S` exits silently with status 1 if the socket is absent; `||` short- circuits at the first failure only — no `|| true` masking the second command's errors once the socket exists. `parse_jackin_sessions` drops the strict `len() != expected` equality in favour of `take(expected)` so trailing footer lines or labels that `Display`-emit a non-`[` continuation line no longer flip the parse to Unavailable; the count check is now a lower-bound (`< expected`), which still catches real format drift but tolerates harmless decoration. The header search lifts a shared `parse_session_count` helper used by both `inspect_agent_sessions` here and `isolation::finalize::has_jackin_sessions`, replacing the duplicate parser that was warned about in finding #3. * `src/isolation/finalize.rs` — `parse_session_count` is now `runtime::attach::parse_session_count`; the local copy is gone. One header parser, one definition of malformed, no silent divergence on edge cases. * `crates/jackin-capsule/src/socket.rs` — accept-loop cap-rejection log now fires exactly once on the saturation transition + once on the recovery transition, with per-drop messages demoted to `cdebug!` so a flood attacker (the exact threat `MAX_CONCURRENT_CLIENTS` defends against) cannot drown the compact-tier log. Per-backoff line also demoted to `cdebug!` — the accept-error clog above already names the failure, so the 1-line-per-failure compact-log invariant holds. `start_listener_at` splits behind a new `start_listener_at_with_limiter` test-only helper that returns the inner `Arc<Semaphore>`. The cap regression test now reads `limiter.available_permits()` directly instead of racing `rx.recv()` against a 300 ms wall-clock deadline — cap-sensitive, not timing-sensitive. Wall-clock `timeout()` windows widen to 2 s for the remaining positive assertions so a slow CI runner does not produce spurious failures. * `crates/jackin-capsule/src/protocol/attach.rs` — new `hello_env_count_over_cap_is_rejected_by_decoder_with_full_payload` variant supplies a fully-populated payload of `MAX_HELLO_ENV + 1` real entries so the per-entry boundary is verified after the read loop, not just at the count declaration. The earlier test only exercised the front-of-loop guard; a regression that moved the cap check below the per-entry loop would slip past it silently. Deferred (parallel-agent territory or out-of-scope for this pass): * `crates/jackin-capsule/src/session.rs` kitty single-pop vs N-push asymmetry (finding #6) and `focus_swap_reset_*` test-name overpromises (finding #12) — `session.rs` is mid-rebase by the parallel agent. * `crates/jackin-capsule/src/main.rs` `--focus` eprintln eaten by alt-screen swap (finding #8) — `main.rs` mid-rebase. * `src/runtime/launch.rs` `fake_docker_for_clean_attached_exit` fixture ordering (finding #14) — `launch.rs` mid-rebase under the env-config migration. Setup-once gating left untouched: `docker/runtime/entrypoint.sh` already gates on `/jackin/state/hooks/setup-once.done` (line 78, runs only if marker absent; line 88 writes the marker on success). The new `test -S` socket gate on the host-side status query is the orthogonal half of the "don't query during early bring-up" rule. Co-authored-by: Codex <codex@openai.com> Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com>
donbeave
added a commit
that referenced
this pull request
May 23, 2026
Trust-but-verify pass on the 15-item /code-review max-effort report that followed the parallel-agent capture commit. Splits cleanly from the in-flight env-config refactor by touching only the host-side session-inventory and snapshot-fanout paths plus the capsule socket layer; parallel-agent territory (main.rs, daemon.rs, session.rs, launch.rs, env_model.rs, derived_image.rs, entrypoint.sh) stays untouched. Findings addressed: * `src/console/manager/state.rs` — fan-out worker panics now surface through the existing `debug_log` path: `h.join()` failures are downcast to a string and re-routed as `Err(anyhow!)` so the slot is no longer dropped by `filter_map(|h| h.join().ok())`. Snapshot fan-out is also bounded by `SNAPSHOT_FANOUT_CHUNK = 8` so a host with dozens of active containers does not spawn dozens of OS threads per 500 ms refresh tick; each chunk's wall-clock cost is still bounded by the slowest fetch in that chunk. The fan-out body moves into a free `fetch_snapshots_parallel` helper so `refresh_instances` stays under the clippy line-count gate. * `src/runtime/attach.rs` — `JACKIN_STATUS_CMD` now gates on `test -S /jackin/run/jackin.sock` so the early-bring-up window (between container start and the daemon binding its socket, plus any pre-`setup-once` time) does not leak operator-visible stderr from a binary that exists but cannot serve yet. `test -S` exits silently with status 1 if the socket is absent; `||` short- circuits at the first failure only — no `|| true` masking the second command's errors once the socket exists. `parse_jackin_sessions` drops the strict `len() != expected` equality in favour of `take(expected)` so trailing footer lines or labels that `Display`-emit a non-`[` continuation line no longer flip the parse to Unavailable; the count check is now a lower-bound (`< expected`), which still catches real format drift but tolerates harmless decoration. The header search lifts a shared `parse_session_count` helper used by both `inspect_agent_sessions` here and `isolation::finalize::has_jackin_sessions`, replacing the duplicate parser that was warned about in finding #3. * `src/isolation/finalize.rs` — `parse_session_count` is now `runtime::attach::parse_session_count`; the local copy is gone. One header parser, one definition of malformed, no silent divergence on edge cases. * `crates/jackin-capsule/src/socket.rs` — accept-loop cap-rejection log now fires exactly once on the saturation transition + once on the recovery transition, with per-drop messages demoted to `cdebug!` so a flood attacker (the exact threat `MAX_CONCURRENT_CLIENTS` defends against) cannot drown the compact-tier log. Per-backoff line also demoted to `cdebug!` — the accept-error clog above already names the failure, so the 1-line-per-failure compact-log invariant holds. `start_listener_at` splits behind a new `start_listener_at_with_limiter` test-only helper that returns the inner `Arc<Semaphore>`. The cap regression test now reads `limiter.available_permits()` directly instead of racing `rx.recv()` against a 300 ms wall-clock deadline — cap-sensitive, not timing-sensitive. Wall-clock `timeout()` windows widen to 2 s for the remaining positive assertions so a slow CI runner does not produce spurious failures. * `crates/jackin-capsule/src/protocol/attach.rs` — new `hello_env_count_over_cap_is_rejected_by_decoder_with_full_payload` variant supplies a fully-populated payload of `MAX_HELLO_ENV + 1` real entries so the per-entry boundary is verified after the read loop, not just at the count declaration. The earlier test only exercised the front-of-loop guard; a regression that moved the cap check below the per-entry loop would slip past it silently. Deferred (parallel-agent territory or out-of-scope for this pass): * `crates/jackin-capsule/src/session.rs` kitty single-pop vs N-push asymmetry (finding #6) and `focus_swap_reset_*` test-name overpromises (finding #12) — `session.rs` is mid-rebase by the parallel agent. * `crates/jackin-capsule/src/main.rs` `--focus` eprintln eaten by alt-screen swap (finding #8) — `main.rs` mid-rebase. * `src/runtime/launch.rs` `fake_docker_for_clean_attached_exit` fixture ordering (finding #14) — `launch.rs` mid-rebase under the env-config migration. Setup-once gating left untouched: `docker/runtime/entrypoint.sh` already gates on `/jackin/state/hooks/setup-once.done` (line 78, runs only if marker absent; line 88 writes the marker on success). The new `test -S` socket gate on the host-side status query is the orthogonal half of the "don't query during early bring-up" rule. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Codex <codex@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
resolve_pathnow normalizes.and..components so paths like../siblingresolve to clean absolute paths (e.g./a/cinstead of/a/b/../c)config mount add --srcnow resolves relative paths (was passing raw input directly)normalize_path/resolve_path/parse_mount_spec_resolvedand 3 integration tests mirroring exact CLI scenarios (workspace addwith relative workdir/mounts,workspace editwith relative mount)AGENTS.mdwith branching policy requiring feature branches for all new workTest plan
cargo test)jackin workspace add ws --workdir . --mount ../siblingresolves to clean absolute pathsjackin workspace edit ws --mount relative-dirresolves correctly🤖 Generated with Claude Code