fix(drill): read curl's message — the exit code cannot tell you what happened #41

Merged
dan-claude-bot merged 1 commit from fix/probe-reads-the-message into main 2026-07-14 11:28:37 +00:00
dan-claude-bot commented 2026-07-14 02:34:56 +00:00 (Migrated from github.com)

Boxes are isolated. They have been since #38. The drill was lying.

The kernel, on the live host:

151: tap77516c4b: ... master claudenet state forwarding ... isolated on
153: tap1b704bcc: ... master claudenet state forwarding ... isolated on

A box probing its sibling:

curl: (7) Failed to connect to 10.87.0.73 port 8088 after 3066 ms: Could not connect to server
ping: 1 packets transmitted, 0 received, 100% packet loss

That is not Connection refused — a refusal comes back instantly, with an RST. This is a frame that went nowhere: three seconds of silence, then give up, and ICMP totally unanswered. Box A cannot reach box B.

The bug

curl exit 7 is "failed to connect". It covers both:

message meaning
Connection refused a RST came back — the packet ARRIVED. Reachable.
Could not connect to server / No route to host nothing came back — DROPPED. Isolated.

Opposite conclusions, one exit code. The drill mapped 7 → arrived, so for two full runs after the isolation fix had landed and was working, it reported a working boundary as a broken one — and sent me chasing a fourth mechanism for a hole that was already closed.

The fix

box_probe returns reachable | refused | dropped by reading curl's message, with ping corroborating. Every isolation probe uses it: sibling, box→host, RFC1918, host→box.

A refusal is instant; an unreachable host burns the timeout. The words say which; the number cannot.

RUNS.md gains trap 12

A curl exit code cannot tell you whether the packet arrived.

Which is the same disease as the eleven traps before it, and as the original bug itself: trusting a proxy for the fact instead of the fact. The box→box hole existed because a code reading stood in for a measurement; it stayed "open" for two extra runs because an exit code stood in for a message.

Expect A3 to read:

PASS  box A cannot reach box B: TCP goes nowhere, ICMP unanswered
  → A3 sibling: BLOCKED — tcp dropped + no icmp reply (security.port_isolation)

🤖 Generated with Claude Code

**Boxes are isolated. They have been since #38. The drill was lying.** The kernel, on the live host: ``` 151: tap77516c4b: ... master claudenet state forwarding ... isolated on 153: tap1b704bcc: ... master claudenet state forwarding ... isolated on ``` A box probing its sibling: ``` curl: (7) Failed to connect to 10.87.0.73 port 8088 after 3066 ms: Could not connect to server ping: 1 packets transmitted, 0 received, 100% packet loss ``` That is **not** `Connection refused` — a refusal comes back **instantly**, with an RST. This is a frame that went nowhere: three seconds of silence, then give up, and ICMP totally unanswered. **Box A cannot reach box B.** ## The bug `curl` exit **7** is *"failed to connect"*. It covers **both**: | message | meaning | | --- | --- | | `Connection refused` | a RST came back — **the packet ARRIVED**. Reachable. | | `Could not connect to server` / `No route to host` | nothing came back — **DROPPED**. Isolated. | Opposite conclusions, one exit code. The drill mapped `7 → arrived`, so for **two full runs after the isolation fix had landed and was working**, it reported a working boundary as a broken one — and sent me chasing a fourth mechanism for a hole that was already closed. ## The fix `box_probe` returns **`reachable | refused | dropped`** by reading curl's **message**, with `ping` corroborating. Every isolation probe uses it: sibling, box→host, RFC1918, host→box. A refusal is instant; an unreachable host burns the timeout. **The words say which; the number cannot.** ## `RUNS.md` gains trap 12 > *A `curl` exit code cannot tell you whether the packet arrived.* Which is the same disease as the eleven traps before it, and as the original bug itself: **trusting a proxy for the fact instead of the fact.** The box→box hole existed because a code reading stood in for a measurement; it stayed "open" for two extra runs because an exit code stood in for a message. Expect A3 to read: ``` PASS box A cannot reach box B: TCP goes nowhere, ICMP unanswered → A3 sibling: BLOCKED — tcp dropped + no icmp reply (security.port_isolation) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/box#41
No description provided.