Skip to content

ST4 worker: follow-ups deferred during review #173

Description

@pdettori

Follow-ups from the ST4 worker (#87, PR #172) that were seen, judged, and deliberately
not fixed
. None affects the acceptance battery or runtime correctness on the paths the
harness exercises today.

Filed as its own issue rather than a note in the repo, because an in-repo list went stale
within one commit: it was generated from an implementation ledger that recorded findings
as they were raised and never reconciled against the code after the final review wave,
so it advertised three blockers that were already fixed. Everything below is audited
against feat/st4-go-worker at review time.

Worth doing, in rough priority order

  1. A dropped refusal leaves an exec unanswered. The receive goroutine sends through a
    non-blocking trySend so it can never stall and miss an Abort — but both frames it
    sends are terminal, and the busy: queue full refusal is uncached, so dropping it
    loses it outright. Worse, the drop correlates with the condition that produces it:
    outbound fills when the pool is saturated, which is when the queue fills. Under
    overload the caller gets nothing and waits out its own deadline — the opposite of the
    design's stated intent. Restructuring frame egress (a priority channel, or a dedicated
    terminal-frame forwarder with its own bounded queue) was declined as too much change
    for the end of a 21-commit branch. The drop is now logged as a warning naming the
    unanswered req_id, so it is at least diagnosable.

  2. gRPC MaxCallRecvMsgSize is unconfigured, so a base64 write payload above the
    4 MiB default kills the whole stream rather than one exec, triggering a reconnect.
    Needs a decision on both ends plus a documented max write size — relay-side
    coordination, which is why it is not in the PR.

  3. SANDBOX_TOKEN is a literal env value in worker-deployment.yaml, filled by sed
    in deploy-incluster.sh, so it lands in the Deployment spec, oc describe, and any
    GitOps mirror. Pre-existing and unchanged by the PR — but the PR is what makes the
    grant real authority, so a secretKeyRef is now warranted.

  4. Unify the session's state plumbing. abortReq/finish close over inflight/mu
    while recvLoop/accept take the map and a *sync.Mutex as positional parameters —
    seven parameters, two of them raw synchronization primitives. For a file whose central
    safety property is "every access is under mu", one convention would make that locally
    checkable instead of requiring a whole-file audit. A small struct with methods collapses
    both signatures. Wanted specifically because this is the reference implementation
    other language ports get written against.

  5. Most tests never join the Serve goroutine. Two of them observe teardown; the rest
    launch Serve and end without waiting, so a teardown deadlock or a wait group that
    never reaches zero would leave a hung goroutine while the suite reported PASS.

Smaller

  1. Drain-watchdog grace is wall-clock, not activity-based. After a timeout fires, a
    drain that is merely slow (not wedged) can be force-closed between reads, dropping
    legitimate trailing output. Narrow — the run is already out of budget — and it is the
    remedy shape the review itself proposed. Resetting the timer on read activity closes it.

  2. The memory coupling is documented but unenforced. BufferCap × 2 streams ×
    MaxConcurrent must fit the pod limit; both sides carry the arithmetic in a comment,
    but nothing stops a future WORKER_MAX_CONCURRENT entry in the Deployment from
    invalidating the 256Mi limit silently.

  3. No //go:build unix constraint. syscall.Setpgid/Kill break a Windows build
    with a compile error rather than a clear "unsupported platform" message. The worker is
    a Linux container, so no second implementation is needed — just the tag.

  4. settle() is a fixed sleep in an otherwise poll-based test file. Justified: there
    is no exported observable for "the inflight slot has been released". An exported test
    hook would let it become a condition wait.

  5. The images install findutils, which none of the harness's operations use.

Platform note, not a follow-up

TestRunReturnsWhenPipeHolderEscapesGroup needs setsid to detach a pipe holder from the
process group, so it skips on macOS and runs on Linux CI. It is the test that hangs
rather than fails if the drain watchdog regresses, so its coverage is real — just not on a
developer's Mac.

Assisted-By: Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions