fix(herdr): close Phase 4 item 2 — actually ask the agent for a handoff
Release already validated and uploaded a §6.1 handoff, but nothing ever told the agent the .orchestra-handoff.json convention existed, so the file it waited on never got written. rotate() now prompts the agent once via a new optional herdr.HandoffRequester capability (CLIAdapter.RequestHandoff) when the file is missing, and defers Release until it appears, mirroring the .orchestra-report.md/B3 ask pattern rather than inventing a handoff. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1rkJ2hBMybnJctPbcy4tT
This commit is contained in:
@@ -113,6 +113,28 @@ This worktree's anchor and TASK.md have already been verified by the plane befor
|
||||
func (a CLIAdapter) Bootstrap(ctx context.Context, s Session, ref string) error {
|
||||
return a.Client.Prompt(ctx, s.PaneID, fmt.Sprintf(bootstrapPrompt, ref), time.Minute)
|
||||
}
|
||||
|
||||
// handoffPrompt is Phase 4 item 2's missing half (AUDIT.md): Release already
|
||||
// validates and uploads a §6.1 handoff the agent wrote, but nothing ever told
|
||||
// the agent that convention exists. rotate() sends this once occupancy crosses
|
||||
// the hard threshold at a turn boundary, mirroring the .orchestra-report.md
|
||||
// convention B3 established for completion — the plane still never invents a
|
||||
// handoff, it only asks the agent to produce one, then validates it in Release.
|
||||
const handoffPrompt = `Orchestra is about to rotate this task to a fresh session (context budget reached).
|
||||
Before you stop, write a §6.1 handoff to ` + HandoffFile + ` at the worktree root, a JSON object with at least:
|
||||
{"meta":{"id":"<any stable string for this handoff>"},"anchor":{"git_sha":"<current HEAD via git rev-parse HEAD>","branch":"<current branch>","dirty":[{"path":"<repo-relative path>","sha256":"<sha256 of its current contents>"}, ...for any uncommitted files]},"knowledge":{...whatever structured context the next agent needs...}}
|
||||
Do not edit TASK.md. Do not fabricate the git_sha or dirty file hashes — read them for real. Once written, stop normally.`
|
||||
|
||||
// RequestHandoff prompts the agent to write HandoffFile before Release reads
|
||||
// it. Optional capability: adapters without a live pane (tests, etc.) can
|
||||
// omit it and rotate() falls back to waiting on the file appearing on its own.
|
||||
type HandoffRequester interface {
|
||||
RequestHandoff(context.Context, Session) error
|
||||
}
|
||||
|
||||
func (a CLIAdapter) RequestHandoff(ctx context.Context, s Session) error {
|
||||
return a.Client.Prompt(ctx, s.PaneID, handoffPrompt, time.Minute)
|
||||
}
|
||||
// Release reads the §6.1 handoff the agent wrote to HandoffFile at the
|
||||
// worktree root, validates its schema and anchor against the worktree's real
|
||||
// HEAD, uploads it to CAS, and only then releases herdr's claim on the pane
|
||||
|
||||
@@ -153,6 +153,10 @@ type Session struct {
|
||||
// session's lease was created — the immutable-spec hash continuity's
|
||||
// pickup validation compares against on the next rotation (§6.2).
|
||||
TaskFileSHA string `json:"task_file_sha,omitempty"`
|
||||
// HandoffRequested is set once rotate() has prompted the agent to write
|
||||
// its §6.1 handoff (HandoffFile) — avoids re-sending the same prompt
|
||||
// every tick while Release keeps waiting for the file to appear.
|
||||
HandoffRequested bool `json:"handoff_requested,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) Prompt(ctx context.Context, pane, text string, wait time.Duration) error {
|
||||
|
||||
Reference in New Issue
Block a user