r45: colab ssh slot + http recovery #
result #
implemented in /Users/dawn/proj/albedo; all edits are uncommitted and unstaged.
no nix rebuild, daemon restart, runtime stop/unassign, or remote file writes occurred.
nothing here makes the change live in the running daemon. its installed
/nix/store/...albedo-server-1.0.0/ code is unchanged. dawn must rebuild/install
albedo and start a kernel from that updated bundle when safe. this verification
loaded the edited module explicitly into this child kernel, not into the daemon.
what changed #
priv/python/albedo_plugins/colab.py: afterremote.connect()raisesRemoteError, a stdlib websocket-upgrade probe checks the ssh endpoint. only HTTP 429 plusalready-active-sessionraises the exportedColabSshSessionError(ColabError,status=429). unrelated refusals or probe transport failures re-raise the original error object unchanged.- successful connects make no extra round trip. the probe is on the failure path only, with a socket timeout capped at 10 seconds and a 4096-byte body read. a successful probe upgrade is immediately closed, never retained as a tunnel.
- new read-only HTTP helpers refresh proxy credentials independently of ssh:
runtime_status(vm),contents(vm, path, content=True),read(vm, path)andpull(vm, remote, local, resume=True).contents(..., content=False)returns metadata without loading file contents.pullreturns the localPathand streams in 1 MiB chunks on a worker thread. - resume validates Content-Range. an ignored Range restarts the local file instead of appending corrupt data. invalid ranges/HTTP errors leave the local file untouched; interrupted downloads retain partial data for retry.
- updated
robot-docs/colab.md, the extension's model-facing instructions, andtest/harness/colab_plugin_test.py.
live before / after #
runtime: gpu-a100-hm-kkb-euw4a2-268zqw5nqszkj.
ssh's symptom is non-deterministic, not merely unhelpful. these variants occurred against the same occupied slot:
| observation | ssh symptom |
|---|---|
| dawn's earlier reproduction | Connection closed by UNKNOWN port 65535 |
this child's real unmodified await colab.connect(vm, timeout=15) |
Connection timed out during banner exchange / Connection to UNKNOWN port 65535 timed out |
full error captured before editing:
RemoteError: ssh target 'colab-gpu-a100-hm-kkb-euw4a2-268zqw5nqszkj' is unreachable: Connection timed out during banner exchange
Connection to UNKNOWN port 65535 timed out
a direct TCP/TLS stdlib websocket handshake returned:
HTTP 429
{"error":"already-active-session"}
a real connect using the final edited source, normal installed remote.connect
and fresh daemon-provided credentials raised:
ColabSshSessionError: Colab allows one ssh session per runtime; a previously held session was not released. This is server-side and does not clear on retry. Use the HTTP file routes to keep working: colab.contents(), colab.read(), colab.pull() (and colab.runtime_status() for liveness). stop()/unassign is the only forceful reset and destroys the VM.
the diagnosis comes from the endpoint, never from pattern-matching ssh stderr. no proxy URL, token, request line, or instance dictionary is interpolated into that message. probe transport errors are discarded in favor of the original RemoteError; new runtime HTTP error messages omit credential-bearing URLs too.
live HTTP verification #
while ssh remained refused, the new helpers successfully read /api/status,
listed Jupyter's root, read file metadata, and read the text file
NGC-DL-CONTAINER-LICENSE (17,232 decoded characters).
real binary transfer using the final source:
metadata = await candidate.colab.contents(vm, "python-apt.tar.xz", content=False)
await candidate.colab.pull(vm, "python-apt.tar.xz", local, resume=False)
- remote metadata size: 346,012 bytes.
- downloaded local size: 346,012 bytes.
- local artifact:
audits/r45_colab_ssh_slot/python-apt.tar.xz. - sha256:
4ab9c915d1295afbf2ca197993454d3659bb8dee4e9cd39ceba9efe5970873cc. - truncated only that local artifact to 12,345 bytes, then called the new
pull(..., resume=True). observed HTTP 206, withContent-Range: bytes 12345-346011/346012. - resumed size and sha256 matched the original full download exactly.
all VM requests were read-only; no training files were modified.
regression checks #
python test/python_test_runner.py test/harness/colab_plugin_test.py: 19 tests passed. local fake HTTP endpoints exercise the actual upgrade request and return the specific 429, an unrelated 429, a 502, and a 101. only the specific 429 is relabelled. tests also cover original-error identity on probe network failure, no probe on successful connect, path escaping, credential refresh, fresh multi-chunk download, 206 resume, ignored Range, invalid ranges, 416/403, and truncated transfer retention.uvx ruff@0.16.10 check priv/python/albedo_plugins/colab.py test/harness/colab_plugin_test.py: clean; both Python files were formatted with the same pinned ruff.uvx ty@0.0.85 check priv/python/albedo_plugins/colab.py test/harness/colab_plugin_test.py: clean.git diff --check: clean.- logs:
tests.log,ruff.log,ty.logbeside this report. - full daemon/e2e suite and Gleam format check were not run.
gleamis not on this kernel's PATH; no nix rebuild or daemon restart was attempted.
remaining limits / activation #
this names the refusal and provides a working independent path; it does not release the occupied ssh slot. forceful reset via stop/unassign destroys the VM, so it was not attempted. a later server-side reap may clear it, but retry itself is not a reset.
HTTP paths are relative to Jupyter's root, not the ssh /content working
directory. resume assumes unchanged remote content; use resume=False for
mutable files. HTTP 416 is conservatively an error, not proof of completeness.
text reads/directory listings return their JSON/text in memory; large/binary
files belong through pull. HTTP recovery is file/liveness access, not a
replacement remote execution transport.
patch: audits/r45_colab_ssh_slot/colab_ssh_slot.patch is the complete
git -C /Users/dawn/proj/albedo diff. report and patch were written to .partial
files and renamed into place. dawn owns the commit and deployment; the running
daemon still does not have this change.
archive note #
The 346,012-byte transfer-test artifact (python-apt.tar.xz, an unrelated Debian package that
happened to be in the runtime's Jupyter root) was verified against the recorded
sha256 4ab9c915d1295afbf2ca197993454d3659bb8dee4e9cd39ceba9efe5970873cc and then deleted from this
archive rather than committed. The digest is the evidence; the bytes are noise in a git tree.