Skip to content

Conversation

@jdoucett
Copy link
Contributor

Summary

  • PR fix(stall): bound the verify retrieve separately from the create (X1D re-ship loop) #37 fixed ship_object's (size-routing) retrieve sharing the create-side HTAR_STALL_SECONDS (2h) silence budget. send_to_fortress — the whole-target and Phase-3 leveled-incremental transport — carries its own, fully self-contained inline twin of the stall-watch logic (run_watched, invariant chore(reclaim): hold AAPF landing-zone raw until promote loop verified #1: no outer-scope references so it stays safe under --globus) and was left on its own hardcoded 7200s default for both the create step and the two retrieve steps (hsi get, then local tar xvf).
  • Confirmed independently hit on repository_X0H_2_spectral-standoff (job 41417829, 2026-07-31, a leveled-incremental, multi-TB whole-target tar): create succeeded, then the round-trip retrieve was killed at exactly "no output for 2.0h" — the same bug class PR fix(stall): bound the verify retrieve separately from the create (X1D re-ship loop) #37 fixed for the routed path.
  • send_to_fortress now takes retrieve_stall_seconds and requires it (raises before any htar_large/hsi/tar call) — mirroring ship_object's contract exactly, no code-side fallback that could silently reinstate the 2h bound.
  • Threaded only into the two retrieve run_watched() calls (hsi get, tar xvf); the create call is untouched (still the hardcoded 7200s default — a create streams per-file progress, so silence there really is a hang).
  • Both real call sites (whole-target Step 2, and Phase-3's ship_level) updated to pass the already-loaded config value through positionally (run only forwards positional args).
  • Design choice: reused stall_defaults.json's existing retrieve_stall_seconds default/config key rather than adding a second knob — it was already documented path-agnostically ("the post-create round-trip verify retrieve"). An operator can still raise it per-asset for X0H-sized multi-TB tars via the same override mechanism that already exists. Happy to split this into a separate default if review disagrees.
  • CLAUDE.md, stall_defaults.json, and config.example.json comments updated to reflect both transports sharing this one bound.

Test plan

  • New tests/test_send_to_fortress_retrieve_stall.py: fakes htar_large/hsi/tar as shell-script stand-ins on PATH (matching test_ship_object_htar_rc.py's approach), since run_watched is a closure local to send_to_fortress and can't be intercepted the way archive._run_with_stall_watch is for ship_object. Each behavioral assertion runs send_to_fortress on a background thread with a bounded join() so a regression that falls back to the 2h default fails fast (not a real 2-hour hang).
    • hsi get retrieve honors the configured bound, not the 2h default
    • tar xvf retrieve honors the configured bound, not the 2h default
    • create keeps its own hardcoded default even given a tiny configured retrieve bound
    • missing/invalid retrieve_stall_seconds raises before any tape work
  • Full existing suite: 428 passed (423 before this change + 5 new), no regressions.

Not merging or deploying — flagging for review per usual process.

🤖 Generated with Claude Code

…rieve too

PR #37 (23a7963) fixed ship_object's routed-object retrieve sharing the
create-side HTAR_STALL_SECONDS (2h) silence budget, but send_to_fortress -
the whole-target and Phase-3 leveled-incremental transport - carries its own
fully self-contained inline twin of the stall-watch logic (run_watched,
invariant #1: no outer-scope references, since it can run remotely under
--globus) and was left on its own hardcoded 7200s default for both the
create AND the two retrieve steps (hsi get, then local tar xvf).

Confirmed hit independently of X1D: repository_X0H_2_spectral-standoff
(job 41417829, 2026-07-31, a leveled-incremental, multi-TB whole-target
tar) had a successful create, then its round-trip retrieve was killed at
exactly "no output for 2.0h" - the identical bug class, on the unfixed twin.

- send_to_fortress now takes retrieve_stall_seconds and REQUIRES it (raises
  before any htar_large/hsi/tar call) - no code-side fallback, mirroring
  ship_object's contract exactly.
- Threaded into the two retrieve run_watched() calls only (hsi get, tar
  xvf); the create call keeps the hardcoded 7200s default - a create
  streams per-file progress, so silence there really is a hang.
- Both real call sites (whole-target Step 2, and Phase-3's ship_level)
  updated to pass the already-loaded config value positionally (run
  forwards positional args only).
- Reused stall_defaults.json's existing retrieve_stall_seconds default
  (21600s/6h) rather than adding a second knob: the config key was already
  path-agnostic ("the post-create round-trip verify retrieve"), and an
  operator can still raise it per-asset for X0H's larger multi-TB tars via
  the same override mechanism.
- CLAUDE.md, stall_defaults.json, and config.example.json comments updated
  to describe both transports sharing this one bound.

Tests: new tests/test_send_to_fortress_retrieve_stall.py - fakes
htar_large/hsi/tar as shell-script stand-ins on PATH (matching
test_ship_object_htar_rc.py's approach), since run_watched is a closure
local to send_to_fortress and can't be intercepted the way
archive._run_with_stall_watch is. Each behavioral assertion runs
send_to_fortress in a background thread with a bounded join so a
regression that falls back to the 2h default fails fast rather than
hanging. Covers: hsi-get retrieve honors the configured bound, tar-extract
retrieve honors it too, create stays on its own default even with a tiny
configured bound, and the absent/invalid-value raises land before any tape
work. Full suite: 428 passed (423 + 5 new), no regressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jdoucett Jarrod S Doucette (jdoucett) deleted the fix/send-to-fortress-retrieve-stall-configurable branch August 6, 2026 12:50
Sign in to join this conversation on GitHub.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant