Give the operator a way to resubmit, and baseline progress at launch

Two gaps F33 left behind.

F34: the renewal gate exempts a lease with no baseline, so a pane that opened
and never started got a full free renewal period. That is the exact case the
gate exists to catch, and it happened live at 01:33:37: the stuck run 5 lease
renewed to 22:03 on a pane that had not moved since 01:13. Baseline the
progress hash at launch, where the pane is already being read.

F35: nothing could re-poke a live pane. Orchestra can put text in an editor and
be wrong about whether it landed, and the only recovery was to destroy the
lease and wait out expiry, roughly an hour. The new "resubmit" action presses
Enter on text Orchestra itself submitted. It changes no lifecycle state so it
appends no event, and it is fenced like an approval: a live worker-owned pane
at the capture revision the operator was looking at.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xsXyr5J1RACo71YeKG3Pu
This commit is contained in:
2026-08-28 01:34:26 +04:00
parent 48326d4301
commit 92f32d6fea
4 changed files with 107 additions and 2 deletions
+26
View File
@@ -475,6 +475,19 @@ func (w *worker) start(ctx context.Context, t domain.Task, ref string) error {
}
log.Printf("launch %s confirmed: %s", t.ID, evidence)
}
// Baseline the progress check at launch, not at the first renewal. The
// renewal gate exempts a lease with no baseline, which handed a pane that
// opened and never started a full free renewal period (F34) — the exact
// case the gate exists to catch. Capturing here costs one pane read and
// makes the first renewal a real comparison.
if l, ok := w.leases[t.ID]; ok && l.ProgressSHA == "" {
if text, progressErr := w.paneProgress(ctx, herdr.CLIAdapter{Backend: backend, Harness: w.harness}, s); progressErr == nil {
l.ProgressSHA = domain.Hash([]byte(text))
w.leases[t.ID] = l
} else {
w.recordError(fmt.Errorf("baseline launch progress %s: %w", t.ID, progressErr))
}
}
if l, ok := w.leases[t.ID]; ok {
if err := w.api.Start(ctx, t.ID, l.Epoch, l.Version, w.sessionEvidence(ctx, t.ID, s)); err != nil {
return fmt.Errorf("ack start: %w", err)
@@ -1093,6 +1106,19 @@ func (w *worker) runCommands(ctx context.Context) {
_ = w.api.ResolveCommand(ctx, command.ID, "stale", "capture revision changed")
continue
}
if command.Kind == "resubmit" {
// Not an approval: the pane is holding input Orchestra already
// submitted and believes it delivered. Press Enter and say so.
if err := w.executionBackend().SendKeys(ctx, session, []string{"Enter"}); err != nil {
_ = w.api.ResolveCommand(ctx, command.ID, "rejected", "resubmit not delivered: "+err.Error())
continue
}
log.Printf("resubmit %s: Enter resent to %s at capture revision %d", command.TaskID, session.PaneID, command.CaptureRevision)
if err := w.api.ResolveCommand(ctx, command.ID, "acknowledged", ""); err != nil {
log.Printf("ack command %s: %v", command.ID, err)
}
continue
}
input, ok := approvalResponse(text, command.Kind)
if !ok {
_ = w.api.ResolveCommand(ctx, command.ID, "rejected", "prompt does not expose an executable approval control")