BOHICA-LABS / BOHICA-LABS/vsdd-factory
Orchestrator yields on external-wait conditions without scheduling a wake (PG-6)
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## Summary
The orchestrator agent has a recurring failure mode: when a pipeline step requires waiting on an external condition (human admin action, scheduled event, GitHub API change), the orchestrator writes prose like "once X happens, the factory will advance" — but does NOT invoke any scheduling primitive (ScheduleWakeup, CronCreate, background polling agent) before yielding control. The factory then idles forever until a human re-engages.
## Concrete instance (just happened)
Running vsdd-factory 1.0.0-rc.21 on ArcavenAE/akey, Phase 2 → Phase 3 transition. The P3-01 CI/CD baseline required branch protection to be applied by a repo admin (pr-manager's service account had only `write`, needed `admin`). I filed `ArcavenAE/akey#6` requesting the human-admin action and wrote: "Once applied, the factory will advance to phase-3-tdd-implementation."
Then I yielded. No tool was scheduled. No background agent was polling. The factory was effectively halted, but the prose implied autonomous progress was waiting in the wings. When the human noticed the language mismatch and asked "when were you planning to check on that issue?" — I had no answer, because no check was scheduled.
## Why this is a defect (not just an oversight)
The orchestrator is supposed to be a coordinator that drives work to completion. When a step has a wait-condition, three options exist:
1. **Schedule a wake.** Use ScheduleWakeup/CronCreate to recheck the external condition periodically. Cheap; works for slow human-paced waits.
2. **Spawn a background watcher.** Long-running agent polling on a tighter cadence. Burns tokens; appropriate when responsiveness matters.
3. **Explicitly state "ping me when done."** No autonomous-flavored language. The human knows they own the next move.
The orchestrator-skill prompt does NOT name this branch point. The default behavior is option (3) but with option-1-flavored language — which is worst of both worlds: implies autonomy that doesn't exist, costs a human attention to notice and re-engage.
## Cousin failure to #343
This is the same shape as #343 (engine yields after state-manager close-out when it should continue) but at a different layer:
- **#343:** engine-level continuation gap — after a sub-agent returns, the engine yields when it should re-prompt the orchestrator.
- **#346:** orchestrator-skill-level gate-template defect — branch-protection-recommended bundle includes a deadlock-inducing setting (1 approver in an autonomous pipeline).
- **THIS (PG-6):** orchestrator-skill-level wait-handling gap — the orchestrator yields on external-wait conditions without encoding the wait as a tool call.
All three share a root pattern: the orchestrator's continuation logic is implicit. It works when the next step is "spawn agent X" because that's a tool call. It breaks when the next step is "wait for Y" because there's no tool call for "wait," only prose.
## Proposed fix
The orchestrator-skill prompt should add a section like:
> ### Wait-Condition Handling
>
> When a step requires waiting on an external condition (human admin action, scheduled event, external API change), you MUST choose one of three explicit handlers BEFORE yielding:
>
> 1. **Scheduled re-check.** Invoke ScheduleWakeup with a check function (poll the external condition; re-engage if met). Use for human-paced waits (hours-to-days cadence).
> 2. **Background watcher.** Spawn a polling sub-agent with run_in_background:true that calls back when the condition is met. Use for responsiveness-sensitive waits.
> 3. **Manual hand-off.** State plainly: "Please notify me when X is done; I will then do Y." Do NOT use phrases like "the factory will advance" or "once applied, the next step happens" — these imply autonomy.
>
> Do not yield with implicit-wait prose. Every wait must have either a scheduled wake, a watcher, or an explicit human-hand-off.
Additional surface area to consider:
- The greenfield-sequence and per-story-delivery workflow files should mark steps that have wait-conditions (e.g., "human approval gate," "external admin action"), so the orchestrator knows to apply the wait-handling protocol at those points.
- A linter / preflight could scan the orchestrator's draft message for "the factory will" + lack-of-recent-scheduling-call and warn.
## Severity
P2 — failure mode is "factory stalls and looks healthy." Doesn't crash, doesn't lose data, just consumes human attention to detect. Hard to detect from agent telemetry (nothing wrong is happening); easy to detect from "wall-clock time since last factory state change is large."
## Related
- drbothen/vsdd-factory#343 (engine yield after sub-agent close-out)
- drbothen/vsdd-factory#346 (gate-template approver-count defect)
- akey product-side instance: ArcavenAE/akey#6 (now resolved — human applied protection via repository ruleset; was the trigger event for surfacing this defect)
- Recorded as PG-6 in akey's HANDOFF-PHASE-3-ENTRY.md
Contributor guide
Assessment
This issue has not been assessed yet.