Zurück zu allen Artikeln

Notizen aus der Praxis

One Blocked Step No Longer Stalls Hayate Agent's Other Work

A blocked step in a sequential plan used to stop every later step, including work that never depended on it. Hayate Agent now lets an independent validator release one ready step while the hold stays open, and eligible saved plans adopt the rule once.

One Blocked Step No Longer Stalls Hayate Agent's Other Work

一つ待ち
冬の小道を
次が行く

One of them waits.
Along the winter lane,
the next one goes on.

A task had two jobs in it. One was to check something against a live service, and that step needed credentials the agent did not have, so it was blocked for a real reason. The other was to publish source changes through the normal CI path, and that job needed nothing from the live service. The plan ran strictly in order, so the publication never started, and the task kept producing blocker notifications while half its work was possible. That is the root cause the author of core pull request #373 describes, and those notifications reported a stuck task while part of it could have run.

I think the fix is the right kind of uncomfortable. The easy answer is to skip a blocked step and carry on, and that answer is wrong, because "blocked" sometimes means "the next step depends on this". #373 lets an independent validator assessment, never the worker, pick one later step that is authorized and independent, moves it ahead, and leaves the blocked step open with its evidence intact. The task still cannot finish while the hold is there. #374 then makes eligible plans that were saved before the change pick up the new rule once, instead of sitting out a stale wait of up to an hour first.

Hayate Agent cover on a dark indigo background with a faint wave pattern at the bottom: small slate 疾風 logo with the label Hayate Agent, then a two-line red Japanese headline, ブロックされた1ステップが / 他の作業をもう止めない (one blocked step no longer stops the other work), above the white English headline One Blocked Step No Longer Stalls Hayate Agent's Other Work, and github.com/hayate-agent at the bottom

All times are Europe/Berlin. The window is 12 November, 08:00, to 12 November, 20:00. #373 merged at 19:20 and #374 at 19:38.

Why strict order was the safe default

Hayate Agent, formerly the VanillaCore Agent, can split a delegated task into a short sequential plan. A worker model runs each step, and an independent validator judges the step's report. When the validator says a step is blocked or waiting on something external, the step does not count as done.

Before #373, that verdict paused the whole execution at that step. Nothing after it ran. For a plan where step 2 really needs step 1's result, this is correct. For a plan where the planner merely wrote the steps down in a convenient order, it strands work that has every permission it needs. The new validator prompt in src/dispatcher-step-prompt.ts names the distinction directly: a derived sequential plan is not itself an operator dependency.

Pausing everything was still the honest default. A dispatcher that guesses which steps are independent can publish code whose precondition never happened. The old behavior wasted time; it did not create wrong effects.

What #373 changes

After the validator confirms a hold, the dispatcher now asks the selected validator, never the worker, one more question: which existing later step of the same task, if any, is ready to run now? It may name one step at most. The prompt tells the validator what must stay binding: real approvals, CI, original ordering requirements, safety and unknown earlier effects. If any prerequisite of a candidate is the blocked step's unfinished result, the validator must not select it. A parent clarification may remove only a precondition the planner invented, never a restriction the operator gave.

If the answer names a valid candidate, the dispatcher moves that one step in front of the blocked one and stores the blocked step's report, correction budget, session and route alongside it. It posts a status line saying that the step stays open and which separate step was released. If the validator returns no verdict, a malformed answer or a step that does not exist, or if the reordered checkpoint would not fit, the hold stays exactly as before.

Infographic on a dark indigo background, red headline A blocked step: what may run next? Left column Before #373: Step 1 live verification, blocked because credentials are missing, arrow to Step 2 publish source, never starts, arrow to Whole task paused with blocker notices and no progress. Right column After #373 and #374: the same blocked Step 1, arrow to Independent validator asked whether ONE later step is ready and independent of the hold; yes leads to Step 2 runs, same identity, step 1 stays open; no or unclear leads to Hold stays as before, no later step runs. An outlined note says eligible older plans (#374) get a one-time policy refresh with the budget kept. Footer: the task completes only when step 1 is resolved; the validator is told not to waive approvals, CI or real dependencies. Example from the #373 tests, source core #373, #374, docs/dispatcher.md

Several protections in the code are worth naming. The released step keeps its original stable identity, and the new tests restart the dispatcher at both checkpoints of a release to check that a finished publication is not run again. A new clarification from the parent conversation after the scheduling checkpoint takes the permit back if the released step has not started. Manual pause, stop and expiry still apply. While the released step runs, the execution is running again, but the original step stays open, so the task cannot complete. Once the released work is done, the execution pauses on the retained hold, and the next wake only reassesses the retained live evidence instead of running that worker again.

The hour #374 takes out

#374 is a follow-up. Its author writes that after #373 was activated, an existing saved assessment still carried an hour-long reserved backoff from the old policy, so the new selection could not run promptly on work that was already waiting. That is an author report, not something this post verified on a live system.

The fix adds a one-time policy marker to the saved plan. During normal recovery, a plan can adopt it when ordinary recovery would already resume it, it is enrolled for current recovery, it still has a later step, and it has a settled assessment whose identity matches the held step's retained intent or settled effect. Its assessment due time then moves to now, and the marker is set in the same write. The attempt count and correction budget stay as they were. Manual pauses, saved questions, stopped or expired work, plans held from older releases and interrupted steps without a matching settled assessment are left alone. New plans carry the marker from the start, so they never need the refresh.

What the tests show

The AI agent that drafts these changelog posts ran the final version of test/dispatcher-sequential.test.ts, as #374 left it, at three commits: the #372 merge just before #373, the #373 merge that v0.1.260 points to, and the #374 merge that v0.1.261 points to. These are controlled local tests with scripted worker and validator replies, not a live system.

Commit Final test file
Before #373 (#372 merge) 85 of 90 pass
v0.1.260 (#373) 89 of 90 pass
v0.1.261 (#374) 90 of 90 pass

Before #373, four of the five failures are #373 cases. Three need the released publication step to run or to survive a restart, for example a publication worker that is called once instead of twice; the fourth needs the readiness question to go to a dedicated validator. The fifth failure is #374's case. Most of the new cases check that nothing happens (a new restriction, a pause, a cancel, an expiry, a malformed selection), and those already pass on the old code, because nothing happening was the old behavior. At v0.1.260 the only failure is #374's case for a saved plan from before the policy. Each commit's own version of the file passes in full: 72 tests before, 84 at v0.1.260 and 90 at v0.1.261.

The authors report full-suite runs of 2,035 passing tests with one existing skip for #373 and 2,054 passing for #374. #373 also says the configured validator model was asked about the real retained execution read-only and chose the source step, while a separate control with a missing required approval stayed blocked. Neither claim was rerun for this post.

What merged and what shipped

The release metadata for v0.1.260 names commit 70045e5 as its source, and the tag resolves to that commit, which is the #373 merge. The same is true for v0.1.261 and commit 42c14cc, the #374 merge. v0.1.260 also contains #372, which merged at 19:14 and has no tag of its own. A tag marks the source of a published image; it says nothing about which installations run it.

#373 and #374 were the last two of 26 merges in the window: 23 in core and 3 in plugins. Several others deal with tasks that stop or wait for the wrong reason, such as #369 ("prevent non-decisions from permanently blocking open work") and #372 ("durable priorities and non-starving post-restart task coordination"), while plugins #94 makes the dispatcher plugin report the concrete reason for a recovery hold. #364 and #367 add a readiness notice after a successful restart. When core was fetched at 20:13 and again at 20:25, main was still at the #374 merge.

Limits

The independence decision is a model's judgement. Whether approvals, CI and ordering allow a candidate is decided by the validator from its prompt and the task data; the host does not check those rules itself. The host enforces the structure around that judgement: the candidate must be an existing later step that is not itself a deferred blocked step, the answer must be well formed, a new parent clarification revokes an unstarted release, and the validator can release only one step each time a hold is confirmed. A validator that misjudges a dependency can release a step too early. The released worker runs before its own step validation, so that later check is another model judgement after the effects, not a guard in front of them.

Verdict

A blocked step should block what depends on it and nothing else. #373 puts that line in the right place, and it is honest about who draws it: the same independent validator that already decides whether a step is done, with the hold kept open and the evidence kept intact. The part I would watch is the prompt carrying the dependency rules, because that is where a wrong release would come from.

Sources used