Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/PONYTAIL_REVIEW_2026-06-20.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
> - **C1** `MerkleTree.get_proof` deleted — its only caller (the stage wrapper) went in Tier 1, so it is now confirmed dead.
> - **R5 (partial)** `bytes_to_sdr` + its roundtrip test deleted (dead deserialization; `sdr_to_bytes` kept — production). **`hamming_distance` KEPT** — it backs real encoder-locality contract tests (similar→close, different→far, identity→0); deleting it would cost coverage, not just lines. Deliberate deviation from the Tier 2 line item.
> - **M3** `apply_modulation` + its test deleted. Rule 10 (anchor gain = 1.0) stays covered by `compute_gain` tests (test_profile) and the production `compute_injection_gain` tests (test_cogexec) — no coverage lost.
> - **Tier 5 (D3)** still parked — needs a roadmap call (will `agents/harness.py` adopt the second socket API?). Untouched.
> - **Tier 5 (D3)** RESOLVED — **removed** (issue #21, decision: no `agents/harness.py` adoption). Deleted `acquire_listen_socket` + `try_launchd_socket`/`try_systemd_socket`/`bind_dev_socket` + their test module (~90 lines). Production `acquire_listening_socket` is the sole path.
> Verification: `cargo test -p hippocampus` 40/0; py_compile + import + dangling-ref grep clean.

Scope: **over-engineering and unnecessary complexity only.** Not correctness,
Expand Down
117 changes: 6 additions & 111 deletions python/harlo/daemon/socket_activation.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
"""Listening-socket acquisition for the Rule-1 daemon.

Two acquisition entry points coexist here, merged from two independent
C1/D69 fixes. Both try, in order: launchd (launch_activate_socket(3),
macOS) → systemd (LISTEN_FDS / fd 3, Linux) → dev fallback (bind the UDS
path ourselves). On macOS the old code only checked the systemd
LISTEN_FDS protocol, so it always fell through to a dev rebind that
unlink+rebind the very socket launchd was holding — Rule 1 (0W idle via
OS socket activation) was never realized on the target platform.
Acquisition tries, in order: launchd (launch_activate_socket(3), macOS) →
systemd (LISTEN_FDS / fd 3, Linux) → dev fallback (bind the UDS path
ourselves). On macOS the old code only checked the systemd LISTEN_FDS
protocol, so it always fell through to a dev rebind that unlink+rebind the
very socket launchd was holding — Rule 1 (0W idle via OS socket
activation) was never realized on the target platform.

- acquire_listening_socket(sock_path, launchd_name) -> (sock, owns_node)
D69-guarded: refuses to hijack a live listener; owns_node tells
the caller whether it may unlink the node on exit (True only in
dev mode — under launchd/systemd the OS owns the node). This is
the production daemon path (daemon/main.py).

- acquire_listen_socket(sock_path) -> (sock, source)
Returns a source label ("launchd"/"systemd"/"dev") for callers
and tests that branch on the acquisition source.

Built for reuse: the agents harness (agents/harness.py:115-127) has the
identical LISTEN_FDS-only bug and should adopt this module in a
follow-up, passing its own socket name ("HarloAgents").

Rule 1: this is pure FD acquisition — no polling, no sleep.
"""

from __future__ import annotations

import ctypes
import ctypes.util
import errno
import logging
import os
Expand Down Expand Up @@ -158,103 +148,8 @@ def acquire_listening_socket(
return sock, True


# ---------------------------------------------------------------------------
# Source-label API (acquire_listen_socket) — retained for callers and tests
# that branch on the acquisition source string.
# ponytail: deferred, test-only today (no production caller). Either adopt in
# agents/harness.py (the intended reuse — see module docstring) or delete
# acquire_listen_socket + try_launchd/systemd/bind_dev + their tests (~85
# lines). Decision tracked in issue #21.
# ---------------------------------------------------------------------------

def try_launchd_socket(name: str = LAUNCHD_SOCKET_NAME) -> socket.socket | None:
"""Return the launchd-activated listening socket, or ``None``.

Wraps ``int launch_activate_socket(const char *name, int **fds,
size_t *cnt)`` from libSystem (Darwin only). Returns ``None`` on any
non-Darwin host, missing symbol, non-zero status, or zero fds — never
raises.
"""
if sys.platform != "darwin":
return None
try:
libc = ctypes.CDLL(
ctypes.util.find_library("System") or "/usr/lib/libSystem.B.dylib"
)
fn = libc.launch_activate_socket
except (OSError, AttributeError):
return None

fn.restype = ctypes.c_int
fn.argtypes = [
ctypes.c_char_p,
ctypes.POINTER(ctypes.POINTER(ctypes.c_int)),
ctypes.POINTER(ctypes.c_size_t),
]
fds_ptr = ctypes.POINTER(ctypes.c_int)()
count = ctypes.c_size_t(0)
try:
rc = fn(name.encode("utf-8"), ctypes.byref(fds_ptr), ctypes.byref(count))
except Exception:
return None
if rc != 0 or count.value < 1:
return None

try:
fd = fds_ptr[0]
sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
except Exception:
return None
finally:
# launch_activate_socket malloc's the fd array; free it.
try:
libc.free.argtypes = [ctypes.c_void_p]
libc.free(ctypes.cast(fds_ptr, ctypes.c_void_p))
except Exception:
pass
return sock


def try_systemd_socket() -> socket.socket | None:
"""Return the systemd-activated socket (fd 3), or ``None``."""
listen_fds = os.environ.get("LISTEN_FDS")
if listen_fds and listen_fds.isdigit() and int(listen_fds) > 0:
return socket.fromfd(3, socket.AF_UNIX, socket.SOCK_STREAM)
return None


def bind_dev_socket(sock_path: str, backlog: int = 5) -> socket.socket:
"""Dev fallback: bind the UDS path directly."""
if os.path.exists(sock_path):
os.unlink(sock_path)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(sock_path)
sock.listen(backlog)
return sock


def acquire_listen_socket(sock_path: str) -> tuple[socket.socket, str]:
"""Acquire the listening socket. Returns ``(sock, source)``.

``source`` is one of ``"launchd"`` / ``"systemd"`` / ``"dev"`` for
logging and tests. Prefer ``acquire_listening_socket`` for the
production daemon path — it adds the D69 live-listener guard.
"""
sock = try_launchd_socket()
if sock is not None:
return sock, "launchd"
sock = try_systemd_socket()
if sock is not None:
return sock, "systemd"
return bind_dev_socket(sock_path), "dev"


__all__ = [
"LAUNCHD_SOCKET_NAME",
"acquire_listening_socket",
"acquire_listen_socket",
"adopt_launchd_socket",
"bind_dev_socket",
"try_launchd_socket",
"try_systemd_socket",
]
69 changes: 0 additions & 69 deletions tests/test_daemon/test_socket_activation.py

This file was deleted.

Loading