fix(issue-23): the onboarding ack is satisfied by what a real agent publishes; one command builder and one started predicate for create and the wrapper
Trial 2 of this branch: cross-server delivery was restored (f7cee00), the
agent completed its onboarding and published started and completed - and
create_session still waited 180 s, called the onboarding unconfirmed, and
tried to write `error` over the completed job (refused by the registry).
delegate_wait_started required the started line to carry data.dispatch_token
(review R1: a stale attempt's started must not vouch for this one). But
publish_event only writes that field when its command line carries
--expect-dispatch-token, and create_session's hand-rolled onboarding command
never did - the wrapper's _pub_cmd does, which is why every wrapper-dispatched
agent's started has the token and no create_session onboarding ever could.
Five reviewers missed it because the fixture wrote the token into the started
line by hand: a fake producer that differs from the real one.
Fix, along the wrapper's existing mechanism rather than a new one:
* delegate_publish_cmd (lib.sh) builds the publish command for an agent, with
--expect-dispatch-token and --attempt-id, and create_session uses it. The
agent's own started now names the dispatch, and publish_event's CAS check
refuses a stale dispatch's event at the source. S7l pins the builder
argument-for-argument against the wrapper's _pub_cmd.
* delegate_started_recorded (lib.sh) is the one definition of "this
dispatch's started is on disk" - JSON-parsed, token-matched when a token is
given - used by delegate_wait_started and by the wrapper's _wait_started in
place of its regex. The wrapper keeps its status and subscriber routes
(remote agents); the shared part is the evidence contract.
* An already-terminal job is left alone when the wait expires (req. 4): no
error over a completed/error/cancelled record.
The fixture now registers the record through registry.py and publishes
started through the real publish_event.py; the only synthetic line left (S7h)
exists to pin key-order independence and says so. S7i pins the trial-2 defect
as the negative it is (old command shape -> started without token -> not
acknowledged); S7j runs the builder's command through the real producer and
is acknowledged on the first probe; S7n shows the wrapper accepting the same
real line and rejecting a stale token; S7m pins no-write-over-terminal. S7f
moves from "publish error" to "leave the terminal job alone", per req. 4.
Option B (verify data.hmac_sig with the job's auth_token, plus record-token
still equal) was weighed and not taken: verify_hmac returns True with no
auth_token - PoC mode, which the trial and every sandbox run in - so it proves
nothing there; in production hmac_sig authenticates the signer but does not
identify the dispatch, so R1 would rest on a current-state check that a stale
line plus an unrotated token passes; and it would diverge from the wrapper
unless the wrapper changed too. Token exposure is not new: every wrapper-
dispatched instruction already carries the dispatch token in the pane, and it
is a per-dispatch CAS nonce, not the HMAC secret.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7cee00dec
commit
1667fda8dd
4 files changed
+303
-86
No files matched your search
@@ -646,11 +646,10 @@ _wait_started() {
|
||||
# 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
|
||||
local ev_log="$REGISTRY_DIR/$job_id.events.log"
|
||||
# A loop job keeps one events.log across iterations: only a `started` that
|
||||
# carries THIS attempt's dispatch token counts (review R1).
|
||||
local started_re='"event": *"started"'
|
||||
[ -n "${_disp_tok:-}" ] && started_re='"event": *"started".*"dispatch_token": *"'"$_disp_tok"'"'
|
||||
# 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")"
|
||||
@@ -660,7 +659,7 @@ _wait_started() {
|
||||
fi
|
||||
# publish_event records `started` here before its wire publish and before
|
||||
# the status sync, so a slow broker cannot delay the acknowledgement.
|
||||
if [ -f "$ev_log" ] && grep -Eq "$started_re" "$ev_log" 2>/dev/null; then
|
||||
if MAM_JOBS_DIR="$REGISTRY_DIR" delegate_started_recorded "$job_id" "${_disp_tok:-}"; then
|
||||
echo "inject: job $job_id recorded 'started' in events.log; treating the prompt as delivered and continuing." >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
Reference in new issue
Block a user