Repository navigation
Never let a host line accept a rejected attempt's output - #24
Conversation
An empty answer used to end a run. In the first F1 runs a stray Enter, or a paste that began with a newline, ended the run while the host was still waiting for the owner's attestation, and the oracle judged a run the host never finished. Empty lines are now ignored, and ending while an attempt is still pending asks for a second "end". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layer B F1 on a real host: the worker ticked its own checkbox, the host rejected the attempt plan_tampered, then verified the rejected worker's file in place and recorded "Dispatched: main — accepted", although the owner's routing required that executor with no fallback. Step 16 said "if you then finish the task yourself, append a main line" with no condition, so taking over the output read as finishing the task. A rejected owner-mandated task now stays pending for the owner. Any other rejected task is finished by the host only through salvage, for the reasons salvage allows, or after the output is given up and the work is redone in the open. The routing rule names the rejected case next to the ineligible one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Layer B host loads passdown from the plugin channel pinned to release/v0.5.0; a new beta version makes the plugin update pick up the dispatch fix before F1 is run again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vunm-dev
left a comment
There was a problem hiding this comment.
Found one P2 issue in the new post-rejection recovery instructions; please address it before merging. The owner-mandated/no-fallback branch correctly makes the task remain pending, but the other branch requires a helper operation that fails for already-released claims.
Validation on this head: tests/skills.sh (153 checks), tests/docs.sh (32 checks), tests/version.sh (4 checks), scripts/check-version.sh, scripts/sync-bundled.sh --check, and shellcheck for the changed runner and canonical helper all passed. All seven GitHub CI checks are green. I also reproduced the finding using the deterministic reference host and fake worker in a disposable fixture: tick-checkbox -> rejected:plan_tampered -> claim.state=released -> release-claim exits 3. This was a simulated test-harness attestation, not real Layer B owner evidence. The real-host F1 rerun on beta.2 remains necessary to validate the behavioral fix. No repository files were modified.
| only through salvage, for the reasons salvage allows, or give it up | ||
| first (`release-claim`, then *Cleanup after a failed attempt*) and do | ||
| the work in the open. Then append `- Dispatched: main (<YYYY-MM-DD>) |
There was a problem hiding this comment.
[P2] Skip release-claim when rejection already released the claim
For a task where host takeover is permitted, a stopped attempt rejected as plan_tampered (also scope_violation or verification_failed) has its claim released automatically by verdict reject. The new redo path nevertheless requires release-claim before cleanup. Reproduced with ref-host dispatch --mode tick-checkbox: the receipt ends rejected:plan_tampered with claim.state=released, and the prescribed release-claim exits 3 with 'does not hold a claim'. Since the skill also says to report helper refusals rather than force past them, following this path blocks an otherwise valid cleanup and redo. Make release-claim conditional on a still-held claim; for an already-released claim, proceed to the same attribution-safe cleanup before redoing the work.
There was a problem hiding this comment.
Confirmed: HOLDING_REASONS in the helper is needs_input blocked invalid_result reemit_wrote integration_failed, so a plan_tampered / scope_violation / verification_failed rejection has already released the claim and release-claim exits 3. Fixed in 1d00309: the redo path runs release-claim only when the rejection kept the claim (those five reasons), and Cleanup after a failed attempt now applies once the claim is released either way. Added a prose check in tests/skills.sh.
A rejection with plan_tampered, scope_violation or verification_failed
releases the claim itself, and release-claim on such an attempt exits 3
("does not hold a claim"). The redo path asked for release-claim
unconditionally, so a host following it hit a helper refusal it must
not force past. Only the claim-holding reasons (needs_input, blocked,
invalid_result, reemit_wrote, integration_failed) need release-claim;
cleanup applies once the claim is released either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All seven gate scenarios (F1, F2, F11, F14a, F14b, F18, F27) pass on a real host: claude -p 2.1.193 with the passdown plugin pinned to release/v0.5.0, the owner attesting every stop by hand. The gate found two protocol gaps, fixed in #24 and #25 before those scenarios were run again; the failing runs are kept as F1-fail-1 and F2-fail-1. docs/evidence/v0.5.0/README.md summarizes the runs, the findings, the harness changes and what was observed but not blocking. Two harness changes come with the evidence: - oracle.sh judges must-not-project on the interrupted attempt. The first oracle failed F14a because the host, correctly, redid the changed task in a new attempt and projected that one; the interrupted verdict must still never be projected, and a tick must be backed by a projected attempt on the current task revision. The first judgment is kept in F14a/oracle.first.txt. - sanitize.sh prepares a run for publication: local paths, the operator's e-mail, the init, hook and rate-limit events, thinking counters and signatures. oracle.sh gives the same verdict on the sanitized records, and they pass the workspace's boundary denylist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PDN-0004 S7 — release-blocking fix found by the Layer B gate (scenario F1).
What Layer B found
F1 on a real host (
claude -p, plugin 0.5.0-beta.1), owner attesting by hand:fakeworker createdsrc/hello.txtand ticked its own checkbox.plan_tampered, restoring[ ]. Correct so far.Dispatched: main — accepted, ticking the task. The fixture's owner routing requiresfakefor task 1.1 with no fallback.Oracle:
FAIL task 1.1 is ticked(no accepted receipt backs it). The run is kept as evidence (docs/evidence/v0.5.0/F1-fail-1, to land with the evidence PR).Cause: dispatch step 16 said "If you then finish the task yourself, append
Dispatched: main … accepted" with no condition. Taking over the rejected output read as finishing the task, and it bypassed salvage, which does not allowplan_tampered.Changes
passdown-dispatchstep 16: a host line never accepts a rejected attempt's output. A rejected owner-mandated task (no fallback) stays pending for the owner. Any other rejected task is finished by the host only through salvage (for the reasons it allows), or afterrelease-claimand cleanup, redoing the work in the open. The routing rule now names the rejected case next to the ineligible one.tests/skills.sh: three prose checks for the rule.endfinishes a run, with a warning while an attempt is pending. Three early F1 runs were cut short by a stray Enter before the host could act on the attestation.0.5.0-beta.2so the pinned plugin channel picks up the fix before F1 runs again.Verification
tests/skills.sh,docs.sh,version.sh,attempt.sh,contracts.sh,interrupt.sh(Layer A, 37 cases) pass;shellcheckclean;scripts/check-version.shpasses.🤖 Generated with Claude Code