fix(issue-23): both ack waits share one contract - the wrapper's status bypass is gone; the G9 guard removes only the docstring node

Review round 3 (planner-reviewer-codex-01, reviewer-opencode-01): R1 blocking,
R2 and the "ONE builder" wording non-blocking. All three reproduced; none
rebutted.

R1. _wait_started still returned 0 as soon as the record left `pending`,
ahead of the shared predicate, so `error`, `cancelled` and another dispatch's
`running` all acknowledged an injection that create's delegate_wait_started
rejects - the two contracts the ack-finding brief said must not diverge. Both
reviewers reproduced it with the real producer and no record manipulation;
my S7n had hidden it by resetting the record to `pending`.

The bypass and the console grep are gone. The wrapper's evidence is now
delegate_started_recorded alone, the same call create makes. For a remote
agent - no shared disk, so no line in events.log - the predicate reads the
subscriber's audit record of the `started` it received. That record is
attributable by construction: the subscriber verifies the HMAC and drops any
event whose data.dispatch_token differs from the job's expected token before
it writes anything. The token itself cannot go into the record (the audit
redactor masks token-named keys), so the subscriber now stamps a boolean
dispatch_verified, and with a token demanded only a verified record counts;
an untokened legacy record fails closed. The registry status is never
evidence; a terminal job is preserved by the terminal logic, not turned into
an acknowledgement.

Tests: W1/W2/W3 are the reviewers' three negatives and the positive, real
producer, record left exactly as it produced it; W4 runs create's wait and
the wrapper's wait side by side on all four and requires the same answer;
W5 pins the remote route (a verified record counts, an unverified or
non-started one does not); W6 drives the real _Watcher and shows it stamps
the flag on a matching started and records nothing for a mismatch; S7n no
longer resets the record. test_issue14's "registry ack over unconfirmed
inject" produced its ack with a bare status flip - the very bypass - and now
produces it the way an agent does, publish_event with the dispatch token;
its scenario and every other assertion are unchanged. test_issue18's remote
e2e accepted the status messages and now expects the shared one.

R2. _code_only blanked a docstring's whole line range, so code sharing that
line - `"""doc"""; call()` - vanished from the scan. It now removes only the
docstring node from the AST and unparses the rest (comments drop out with
it, code strings stay); test_g9b pins the four same-line shapes.

The builder comment claimed one builder for create and the wrapper; the
wrapper keeps _pub_cmd and S7l pins the two equal argument-for-argument. The
comment now says that.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
GodopuandClaude Fable 5.1 committed 2026-09-22 16:43:00 +00:00
1 parent 4805fd4511
commit 087eacaf21
7 files changed
+250 -72

No files matched your search

@@ -633,40 +633,33 @@ _disk_status() {
# ISSUE-18: delivery is confirmed by the protocol, not the screen. After the
# prompt was handed over (herdr accepted the submission, or the dispatch was
# published for a remote session) the job's own `started` must arrive within
# the ack timeout T: the registry leaves `pending` (the agent's publish_event
# syncs it on this host), a started line lands in events.log, or the
# subscriber prints a started line (a remote agent - no shared disk). No
# `started` within T is a delivery failure: fail closed, never re-inject
# (single-injection contract). The status is not pinned to this dispatch and
# may come from an external writer; the terminal handling after this still
# keeps such an error/cancelled as it is rather than turning it into success.
# the ack timeout T. The evidence is lib.sh's delegate_started_recorded - the
# same predicate create_session's onboarding ack uses, so the two waits share
# one contract (ack-finding req. 2, review R1): the local publisher's line in
# events.log, or the subscriber's HMAC-verified, dispatch-attributed audit
# record of a `started` it received (a remote agent has no shared disk). The
# registry status is not evidence - a record leaves `pending` when another
# writer closes it (error, cancelled) or another dispatch claims it, none of
# which says this agent saw this prompt. No `started` within T is a delivery
# failure: fail closed, never re-inject (single-injection contract). A job
# that is already terminal is handled by the terminal logic after this, not
# turned into a success here.
_wait_started() {
local job_id="$1" ack_s="${2:-$ACK_TIMEOUT}" sub_log="${3:-}" deadline wall st
local job_id="$1" ack_s="${2:-$ACK_TIMEOUT}" sub_log="${3:-}" deadline wall
# sub_log is retained for callers' signatures; the subscriber's evidence is
# read from its audit record, which is attributable, not from its console.
deadline=$(( $(date +%s) + ack_s ))
# The ack wait never outlives this dispatch's wall clock (START_TIME + TIMEOUT).
wall=$(( ${START_TIME:-$(date +%s)} + ${TIMEOUT:-3600} ))
[ "$deadline" -gt "$wall" ] && deadline=$wall
# A loop job keeps one events.log across iterations: only a `started` that
# carries THIS attempt's dispatch token counts (review R1). The predicate is
# lib.sh's delegate_started_recorded - the same one create_session's
# onboarding ack uses, so the two waits share one definition of evidence.
local budget=$(( deadline - $(date +%s) ))
while :; do
st="$(_disk_status "$job_id")"
if [ -n "$st" ] && [ "$st" != "pending" ]; then
echo "inject: job $job_id advanced to '$st' in the registry; treating the prompt as delivered and continuing." >&2
return 0
fi
# publish_event records `started` here before its wire publish and before
# the status sync, so a slow broker cannot delay the acknowledgement.
if MAM_JOBS_DIR="$REGISTRY_DIR" delegate_started_recorded "$job_id" "${_disp_tok:-}"; then
# publish_event records `started` locally before its wire publish and
# before the status sync, so a slow broker cannot delay the acknowledgement.
if MAM_JOBS_DIR="$REGISTRY_DIR" delegate_started_recorded "$job_id" "${_disp_tok:-}" "${LOGS_DIR_ABS:-}"; then
echo "inject: job $job_id recorded 'started' in events.log; treating the prompt as delivered and continuing." >&2
return 0
fi
if [ -n "$sub_log" ] && [ -f "$sub_log" ] && grep -Eq '^[^ ]+ job=[^ ]+ seq=[^ ]+ started( |$)' "$sub_log" 2>/dev/null; then
echo "inject: subscriber received started for job $job_id; treating the prompt as delivered and continuing." >&2
return 0
fi
if [ "$(date +%s)" -ge "$deadline" ]; then
ACK_WAITED_S="$budget"
return 1