From 1926289e4018b32851e284766a0b7a6d4fead5d4 Mon Sep 17 00:00:00 2001 From: choiyounggi <74581798+choiyounggi@users.noreply.github.com> Date: Sat, 8 Aug 2026 00:42:01 +0900 Subject: [PATCH] knowledge: ingest 1 verified insight (2 dropped as in-flight duplicates) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New: infrastructure/agent-orchestration/unattended-worker-questions — an unattended worker's in-band question reaches nobody: with a TTY the chooser waits indefinitely while liveness checks pass, without one it self-answers empty. Classify a live-terminal stall from the terminal tail before restarting, unblock with an allowlisted key sequence, re-send the prompt the chooser swallowed, and prevent recurrence with a durable out-of-band question record. Dropped: the worktree_escape read-only-escalation candidate (in flight in #47 and #51) and the Orca dispatch-binding taxonomy candidate (in flight in #51/#47). log.md records a contradiction between #47 and #51 on the guardrail mechanism, settled against the rule source in favour of #51. --- .dev-loop/INGEST_REPORT.md | 148 +++++++++++++----- log.md | 2 + .../control-signals-vs-primary-artifacts.md | 2 +- .../pane-delivery-confirmation.md | 2 +- .../agent-orchestration/shared-run-state.md | 2 +- .../unattended-worker-questions.md | 89 +++++++++++ wiki/infrastructure/index.md | 1 + 7 files changed, 200 insertions(+), 46 deletions(-) create mode 100644 wiki/infrastructure/agent-orchestration/unattended-worker-questions.md diff --git a/.dev-loop/INGEST_REPORT.md b/.dev-loop/INGEST_REPORT.md index 55ccfd1..3c6b25b 100644 --- a/.dev-loop/INGEST_REPORT.md +++ b/.dev-loop/INGEST_REPORT.md @@ -1,53 +1,115 @@ -# Knowledge consolidation — 15 open PRs (#17–#40) → one reconciled state +# Knowledge flush — 3 insight(s): 1 ingested, 2 dropped as in-flight duplicates -The 15 open `knowledge/*` PRs (created 2026-08-04 → 2026-08-05, before the -harvest processed-store dedupe fix in #41) contained 123 file-versions of ~75 -unique pages, with the same insight landing at up to 3 different paths across -up to 8 PRs. Per-PR review would re-import those duplicates, so — as with the -#6–#13 consolidation — this branch carries the reconciled end-state and the 15 -PRs are closed in its favor. +Queue drained: `~/.dev-loop/queue/f1a3ae46-….jsonl` (3 pending rows). One new page, +no existing page rewritten, one contradiction between two open PRs flagged in `log.md`. ## Verified best-practice -Every adopted page's sources were carried from its originating PR's flush, where -they were live-verified at flush time; no new URLs were introduced during -consolidation (checked mechanically: every `http(s)` URL in every merged page -appears in a source PR's diff; every added body line in amended pages traces to -a source PR hunk — orphan-line verification). Confidence fields were kept as the -originating flushes set them, except client-side-rate-limiting where the union -of provider-doc citations (Okta, Auth0, GitHub, OpenAI, RFC 6585) supports -`verified` for the load-bearing claims. One subagent's fabricated content (12 -files matching neither main nor any PR, with invented source URLs) was detected -by the same verification and replaced with true PR content. +### A — ingested: a worker agent's in-band question reaches nobody + +**Claim.** When an agent worker runs unattended and raises a question through its own +interactive question UI, no answer arrives. With a TTY (a tmux pane) the chooser waits +indefinitely while every liveness check passes; without a TTY the tool self-resolves with +empty answers and the agent proceeds as if answered. The channel a worker uses to ask its +coordinator for a decision therefore has to be out-of-band and durable. + +**Sources checked and what each supports.** + +| Source | Supports | Result | +|--------|----------|--------| +| https://github.com/anthropics/claude-code/issues/50728 | no-TTY branch | `AskUserQuestion` "auto-resolves immediately with empty answers", ~37 ms, before a `can_use_tool` callback or `PreToolUse` hook can intervene; agent receives `User has answered your questions: .` Environment: `claude-agent-sdk` 0.1.63, bundled CLI 2.1.114, Docker. **Closed as not planned** — the behaviour is not being changed, which is what makes the workaround durable knowledge | +| https://github.com/anthropics/claude-code/issues/29530 | no-TTY branch, second report | Same tool "does not render any interactive UI (question text, selectable options)" and returns empty (CLI 2.1.63). **Open**, labelled `bug`, `has repro` | +| https://man7.org/linux/man-pages/man1/tmux.1.html | the unblock mechanism | `send-keys` writes key events into a pane; named keys go without `-l` (with it tmux sends the literal characters) | +| dev-loop 1.4.2 `skills/orchestrate/scripts/` (read in this checkout) | the TTY branch + the remedy, as shipped behaviour | `orca-worker-stalled.sh` header records the measurement: three workers held a live PTY on an interactive prompt for **75 minutes** with byte-identical diffs while every alive/dead check passed, and `lastOutputAt` was "measured and rejected" because a TUI repaints its spinner. `ask-coordinator.sh` is the durable channel (atomic `questions/.json`, refuses task names with `/`, `.`, `..`); `watch-status.sh` surfaces it as its own exit code; `send-prompt.sh keys` validates every key against the allowlist `Up Down Left Right Enter Escape Tab Space 0-9 y n` before sending any, one `send-keys` per key. `SKILL.md` supplies the "at 600 s and 900 s both workers proceeded on a conservative assumption" measurement | +| Field observation, this session (`lo-4-qag1`) | the re-send step | 30-minute stall on a numbered chooser; two rounds of number-then-Enter (selection, then confirmation) cleared it; the prompt queued in the input line before the chooser opened was never submitted and the phase advanced only after it was re-sent | + +**Confidence: `verified`.** Two published issues with reproductions cover the no-TTY branch; +the TTY branch and the remedy are backed by shipped code plus its own recorded measurements. +The one part resting on this session alone — that answering the chooser leaves a previously +queued prompt unsubmitted — is written as a single `Do this` step and attributed to the field +observation in `Sources`, not asserted as doc-backed. + +### B — dropped: `worktree_escape` escalating on read-only cross-worktree access + +Not ingested, and the candidate's framing is **wrong**. It claimed the rule "fires `ask` even on +read-only access". Read against the rule source (`plugins/guardrails/hooks/bash-guard.sh`, +`worktree_escape`, groundwork checkout): after stripping the worker's own worktree path and any +configured `allowPaths`, a surviving `$main_root/` mention fires **only if** a write verb +(`rm|mv|cp|tee|mkdir|touch|install|dd`) or a redirect to an absolute path also matches — and the +two tests are matched independently over the whole command string. A bare `grep`/`awk`/`git status` +read does not fire; a read sharing a command line with any write verb does. That is exactly what +open PR #51 already documents, so the candidate adds nothing and would re-introduce a wrong mechanism. + +### C — dropped: Orca dispatch-binding failure taxonomy + +Not ingested. The candidate's content (check for the idle prompt before binding; `runtime_unavailable` += the turn's tail still occupies the terminal, wait and bind a *new* unit; `agent_unconfigured` = the +agent process is dead, close the terminal and create a new worker-mode agent; always pass the worktree +with the terminal) is carried by open PRs #51 and #47 in equal or better form, with the same field +evidence. Verified only far enough to confirm the overlap. ## Existing-layer check -- Merged-main near-dup scan before consolidation: pairwise Jaccard over - title + "When this applies" across all 141 merged pages → **0 flagged pairs**; - previously merged content carries no duplication. -- Cross-PR dedup during consolidation: 10 duplicate clusters collapsed to one - canonical page each (rate limiting 8→1, call-site enumeration 7→folded into - the canonical merged in #20, stderr/exit-0 diagnostics 4→1, sysroot 2→1, - env-off-switch 2→1, completion predicates 2→1, robots.txt 2→1, - harness-mediated results 2→1, leaked artifacts 2→1, orchestration category - naming unified). Three near-pairs kept distinct after trigger comparison, - with mutual `related:` links (differential setup vs interpretation; expansion - semantics vs off-switch design; import-time tactics vs level choice). -- 24 existing pages received union-merged amendments; additions already present - in main (from #16/#20) were skipped, and all non-canonical `related:` ids - were remapped to canonical page ids (post-merge broken-link scan: 0). +Routed via `INDEX.md` → `infrastructure` (its route line already names multi-agent orchestration: +worker liveness signals, shared run state, tmux pane delivery, completion gates, worktree-isolated +workers) → `wiki/infrastructure/index.md` → the `agent-orchestration` category. Every page in that +category whose "load when" line could overlap was opened in full, plus the one cross-domain page the +no-TTY branch touches. + +Pages read: infrastructure-agent-orchestration-worktree-isolated-workers, infrastructure-agent-orchestration-pane-delivery-confirmation, infrastructure-agent-orchestration-control-signals-vs-primary-artifacts, infrastructure-agent-orchestration-shared-run-state, platforms-processes-non-interactive-cli-invocation + +| Page read | Overlap with insight A | Verdict | +|-----------|------------------------|---------| +| `…-pane-delivery-confirmation` | Owns "did the keystroke land" — busy indicator vs pane diff, serialising sends. Says nothing about *why* the target is waiting or who is supposed to answer | Adjacent, not a home. Linked both ways; step 4's "busy indicator → keep waiting" row defers to it | +| `…-control-signals-vs-primary-artifacts` | Owns done/alive/dead verdicts and has a stalled-third-state row (fresh heartbeat + unchanged artifact) | Adjacent. The wedged-on-a-question case is one cause of that state, referenced from the new page's edge cases; linked both ways | +| `…-shared-run-state` | Owns the layout of the run's shared directories (`status`, `briefs`, `escalations`) and run-id namespacing | Adjacent — the `questions/` record is a sibling of those. The new page defers path layout to it rather than restating; linked both ways | +| `…-worktree-isolated-workers` | Brief/output contract and guardrail direction. No question-channel content | No overlap | +| `platforms-processes-non-interactive-cli-invocation` | Covers a prompt-capable CLI being *invoked* from a script (detach fd 0, close the prompt channel, bracketed-paste submit). Its concern is the harness's invocation; ours is a question raised mid-turn by a worker already running | No overlap; one-way `related:` link added from the new page | + +**Merge-before-create judgement.** No existing page carries the trigger "a worker asked a question +and nobody is there". The three adjacent pages each own one slice (delivery, liveness verdict, state +layout) and splitting this insight across all three would violate one-case-per-page in each of them. +New page created, all three linked bidirectionally. + +**Conflicts flagged.** One, and it is between two *open PRs*, not with merged content: #47's +`worktree-isolated-workers` row says the guardrail's read/write asymmetry is version-dependent and +that "a conservative rule treats any cross-worktree path reference … reads included"; #51's row says +reads still pass alone and fire only alongside a write verb or absolute redirect. Reading the rule +source settles it in #51's favour (see "B — dropped" above). Recorded in `log.md` as a +`contradiction` entry for resolution at merge time; nothing overwritten here. + +**Links added.** `related:` now bidirectional between the new page and `…-pane-delivery-confirmation`, +`…-control-signals-vs-primary-artifacts`, `…-shared-run-state`; one-way to +`…-session-completion-gates` and `platforms-processes-non-interactive-cli-invocation`. + +## Open-PR check + +`gh pr list` is unusable here (the ambient `gh` token returns HTTP 401 on the GraphQL API), so open +PRs were listed through the GitHub MCP REST endpoint and every knowledge head was fetched and diffed +locally: `git fetch origin ` then `git diff origin/main FETCH_HEAD -- wiki/`. + +Open `knowledge/*` heads at flush time (11): #62, #61, #58, #57, #56, #55, #52, #51, #50, #49, #47. +(#63 is `feat/role-model-selection`, not a knowledge PR.) + +| Candidate | Overlapping open head(s) | Verdict | +|-----------|--------------------------|---------| +| A — unattended worker questions | none. Every open head's `wiki/` diff was grepped for `menu` / `interactive` / `send-keys` / `prompt-capable`; the only hits are `related:` id lists and an unrelated job-control row in #57 | **new** — ingested | +| B — `worktree_escape` on read-only access | **#47** (`worktree-isolated-workers` edge row + a field-evidence source line with the same Wave-2 `awk`/`grep`/`git status` evidence) and **#51** (same page, mechanism-accurate rows plus a local reproduction) | **drop** — pending duplicate, twice over, and the candidate's own wording is the mechanism #51 corrects. Nothing unique to fold; the correction that *is* new (the rule source settles #47 vs #51) is recorded in `log.md` rather than pushed into either branch | +| C — Orca dispatch-binding taxonomy | **#51** (`pane-delivery-confirmation`: four new edge rows — bind only at the idle prompt, `runtime_unavailable` → wait and bind a fresh unit, `agent_unconfigured` → replace the agent, pass the worktree with the terminal — plus an `Instead of` row) and **#47** (`control-signals`: the done-signal-is-not-release-time row) | **drop** — pending duplicate with nothing new | + +No sibling duplicate PR was opened, and nothing was pushed to another contributor's branch. ## Routing decision -- New categories: `infrastructure/agent-orchestration` (5 pages; unified the - competing `orchestration`/`agent-orchestration` names), `databases/data-survey` - (1), `qa/deliverables` (1). All other pages route into existing categories. -- Canonical-path decisions: rate limiting → `backend/common/reliability/` - (sits beside timeouts-and-retries; 6 of 8 variants chose it); stderr - diagnostics → `platforms/processes/` (concern spans beyond shells); leaked - artifacts → `testing/data/artifact-leakage-from-a-suite`; call-site - enumeration → the existing `backend/common/change-impact/` page. -- All 38 new pages listed in their domain indexes (nearest-index rule; backend - routes via its python sub-index for bytecode-cache-staleness); INDEX.md domain - summaries updated for infrastructure/qa/databases. Full-wiki lint: frontmatter, - ids, related-links, index coverage, size, qualifiers, staleness → 0 findings. +| Insight | Target | New category? | +|---------|--------|---------------| +| A | `infrastructure` / `agent-orchestration` / **new page** `unattended-worker-questions.md` (id `infrastructure-agent-orchestration-unattended-worker-questions`) | No — `agent-orchestration` already exists and its scope line in `INDEX.md` covers worker liveness signals and tmux pane delivery. This is a sixth page in it | +| B | none (retired) | — | +| C | none (retired) | — | + +`applies_to: [tmux, general]` — the detect/unblock half is multiplexer-specific, the +channel-design half is not. Domain index gained a "load when" row for the new page; `log.md` +gained one `ingest` entry and one `contradiction` entry. + +Files changed: `wiki/infrastructure/agent-orchestration/unattended-worker-questions.md` (new, 76 body +lines), `wiki/infrastructure/index.md`, three `related:` back-links, `log.md`. diff --git a/log.md b/log.md index c930fc2..b1e443e 100644 --- a/log.md +++ b/log.md @@ -43,3 +43,5 @@ Append-only. Format: `## [YYYY-MM-DD] |>>)[[:space:]]*[\"']?/"` also matches — the two tests are independent, which is why a read sharing a command line with any write verb escalates. Resolve in favour of #51's wording when merging. diff --git a/wiki/infrastructure/agent-orchestration/control-signals-vs-primary-artifacts.md b/wiki/infrastructure/agent-orchestration/control-signals-vs-primary-artifacts.md index 70633d6..3d1ef14 100644 --- a/wiki/infrastructure/agent-orchestration/control-signals-vs-primary-artifacts.md +++ b/wiki/infrastructure/agent-orchestration/control-signals-vs-primary-artifacts.md @@ -9,7 +9,7 @@ sources: - https://code.claude.com/docs/en/hooks - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html last_verified: 2026-08-05 -related: [infrastructure-agent-orchestration-shared-run-state, infrastructure-agent-orchestration-pane-delivery-confirmation, infrastructure-agent-orchestration-session-completion-gates, platforms-shells-command-text-inspected-before-execution, platforms-tools-harness-mediated-tool-results, debugging-methodology-hypothesis-testing] +related: [infrastructure-agent-orchestration-unattended-worker-questions, infrastructure-agent-orchestration-shared-run-state, infrastructure-agent-orchestration-pane-delivery-confirmation, infrastructure-agent-orchestration-session-completion-gates, platforms-shells-command-text-inspected-before-execution, platforms-tools-harness-mediated-tool-results, debugging-methodology-hypothesis-testing] --- # Deciding a Worker Is Done, Alive, or Dead from a Status File or Watcher Verdict diff --git a/wiki/infrastructure/agent-orchestration/pane-delivery-confirmation.md b/wiki/infrastructure/agent-orchestration/pane-delivery-confirmation.md index 077bf05..7b37cba 100644 --- a/wiki/infrastructure/agent-orchestration/pane-delivery-confirmation.md +++ b/wiki/infrastructure/agent-orchestration/pane-delivery-confirmation.md @@ -8,7 +8,7 @@ sources: - https://man7.org/linux/man-pages/man3/termios.3.html - https://man7.org/linux/man-pages/man1/tmux.1.html last_verified: 2026-08-05 -related: [platforms-shells-option-like-argument-values, infrastructure-agent-orchestration-session-completion-gates, platforms-processes-non-interactive-cli-invocation] +related: [infrastructure-agent-orchestration-unattended-worker-questions, platforms-shells-option-like-argument-values, infrastructure-agent-orchestration-session-completion-gates, platforms-processes-non-interactive-cli-invocation] --- # Confirming a Keystroke Sent to a Terminal Pane Was Actually Consumed diff --git a/wiki/infrastructure/agent-orchestration/shared-run-state.md b/wiki/infrastructure/agent-orchestration/shared-run-state.md index e026b0d..636805d 100644 --- a/wiki/infrastructure/agent-orchestration/shared-run-state.md +++ b/wiki/infrastructure/agent-orchestration/shared-run-state.md @@ -8,7 +8,7 @@ sources: - https://git-scm.com/docs/git-worktree - https://man.openbsd.org/tmux last_verified: 2026-08-05 -related: [infrastructure-agent-orchestration-control-signals-vs-primary-artifacts, infrastructure-agent-orchestration-session-completion-gates, infrastructure-agent-orchestration-worktree-isolated-workers, backend-common-concurrency-distributed-locks, backend-common-jobs-scheduled-job-overlap] +related: [infrastructure-agent-orchestration-unattended-worker-questions, infrastructure-agent-orchestration-control-signals-vs-primary-artifacts, infrastructure-agent-orchestration-session-completion-gates, infrastructure-agent-orchestration-worktree-isolated-workers, backend-common-concurrency-distributed-locks, backend-common-jobs-scheduled-job-overlap] --- # Orchestration State Kept in a Shared Directory Inside the Repository diff --git a/wiki/infrastructure/agent-orchestration/unattended-worker-questions.md b/wiki/infrastructure/agent-orchestration/unattended-worker-questions.md new file mode 100644 index 0000000..b37d348 --- /dev/null +++ b/wiki/infrastructure/agent-orchestration/unattended-worker-questions.md @@ -0,0 +1,89 @@ +--- +id: infrastructure-agent-orchestration-unattended-worker-questions +domain: infrastructure +category: agent-orchestration +applies_to: [tmux, general] +confidence: verified +sources: + - https://github.com/anthropics/claude-code/issues/50728 + - https://github.com/anthropics/claude-code/issues/29530 + - https://man7.org/linux/man-pages/man1/tmux.1.html +last_verified: 2026-08-08 +related: [infrastructure-agent-orchestration-pane-delivery-confirmation, infrastructure-agent-orchestration-control-signals-vs-primary-artifacts, infrastructure-agent-orchestration-shared-run-state, infrastructure-agent-orchestration-session-completion-gates, platforms-processes-non-interactive-cli-invocation] +--- + +# A Worker Agent Asks a Question With No Human at Its Terminal + +## When this applies + +An orchestrator runs agent workers unattended (tmux panes, a task runner, an SDK +subprocess) and one worker raises a question through its own in-band question UI — +a numbered chooser, a confirmation screen, a trust or re-auth prompt. Also when a +worker is judged stalled with a live terminal and no task-level error, or when a +worker reports a decision it "assumed" that nobody was asked about. + +## Do this + +1. **Treat an in-band question as unanswerable and design an out-of-band channel + for it.** Give the worker one command that writes a durable question record the + coordinator polls — `{ts, taskId, question, options, worktree}` in a + `questions/` directory beside the run's status directory + ([infrastructure-agent-orchestration-shared-run-state]) — and have the worker + end its turn after writing it. The record survives the worker's turn; a UI + waiting for a keystroke does not. +2. **State the channel in the worker's first prompt**, naming the command and the + rule that a decision needing the coordinator is written to that channel rather + than raised locally. A worker follows the prompt it was given; without the rule + it reaches for its default question UI. +3. **Make a pending question a distinct wake reason** in the watcher, separate + from "failed" and from "all tasks reached the phase", so it is handled and + cleared rather than aggregated into a timeout. +4. **Classify before acting on a stall — read the terminal tail first.** "Wedged + on a question" and "finished but never reported" are identical from outside and + need opposite responses: + +| Terminal tail shows | Do | +|---------------------|----| +| A question UI with selectable options | Unblock it by key (step 5), then re-drive the interrupted work (step 6) | +| The idle prompt, work visibly complete | Ask for the completion signal; the worker finished and skipped its report | +| The busy/working indicator | Not a stall — keep waiting ([infrastructure-agent-orchestration-pane-delivery-confirmation]) | +| A usage-limit or re-auth notice | Idle waiting, not a crash; resume after the stated reset | + +5. **Unblock a question UI with an allowlisted key sequence, validated whole + before any key is sent.** Restrict the allowlist to navigation and answer keys + (`Up Down Left Right Enter Escape Tab Space 0-9 y n`), send one key per call so + ordering is deterministic and a failure names the key that did not land, and + re-read the terminal until the idle prompt returns — a chooser can have a + selection step and a confirmation step, and one key answers only the first. +6. **Re-send the prompt that was in flight when the question opened.** Text typed + or pasted into the input line before the UI opened is not submitted by the keys + that answer the UI; the turn ends quietly with the work never started. Confirm + from the artifact the prompt was supposed to produce, not from the terminal. + +## Edge cases + +| Case | Then | +|------|------| +| The worker runs with no TTY (SDK subprocess, container, CI) | The question tool does not block — it resolves immediately with empty answers and the agent continues as if answered, so the failure is a silent wrong decision instead of a stall. The out-of-band channel is the fix in both substrates | +| Liveness and heartbeat checks all pass while nothing progresses | A live PTY on a question UI is alive-and-not-progressing, a third state distinct from alive and dead; add a per-agent activity check to see it | +| The stall detector keys off terminal output timestamps | A TUI repaints its spinner continuously, so a wedged worker reports output "0 seconds ago" — key off the agent's own state timestamp instead | +| The out-of-band ask has a timeout and it expires | A timeout leaves the question pending; it is not an answer. Resume the same question rather than deciding it in the worker or asking it again | +| Answering the question requires a decision the coordinator also cannot make | Record it against the task and hand the whole record to the human once, rather than blocking each worker separately | +| The question record's task id is attacker- or environment-derived | It becomes a filename — reject `/`, `.`, `..`, and empty before writing, so a record cannot escape the questions directory | + +## Instead of + +| If you are about to | Do this instead | Why | +|---------------------|-----------------|-----| +| Let a worker raise its question through its own interactive UI | Have it write a durable question record and end its turn | The UI needs a human at that terminal; with a TTY it waits indefinitely, and without one it self-answers empty | +| Restart or replace a worker that a stall check flagged | Read the terminal tail and classify first | A worker waiting on a question is intact and one keystroke from resuming; restarting discards its completed work | +| Send free text to answer a chooser | Send allowlisted key events, validated as a set before the first is sent | A chooser reads key events, and a half-delivered sequence leaves it in a state neither side can name | +| Tell a worker to "decide it yourself and note the assumption" | Give it the question channel and have it wait for the answer | Measured on a 3-worker run: at 600 s and 900 s both workers instead proceeded on a conservative assumption and reported the guess after the fact | + +## Sources + +- https://github.com/anthropics/claude-code/issues/50728 — `AskUserQuestion` in a headless/no-TTY environment (Docker, `claude-agent-sdk` 0.1.63, bundled CLI 2.1.114): "auto-resolves immediately with empty answers", completing in ~37 ms before a `can_use_tool` callback or `PreToolUse` hook can intervene; the agent receives "User has answered your questions: ." and continues. Closed as not planned +- https://github.com/anthropics/claude-code/issues/29530 — same tool "does not render any interactive UI (question text, selectable options)" and returns an empty answer (CLI 2.1.63, open) — a second report that the in-band channel cannot be relied on to reach a human +- https://man7.org/linux/man-pages/man1/tmux.1.html — `send-keys` writes key events into a pane; named keys are sent without `-l`, which sends the literal characters instead +- Shipped implementation, dev-loop 1.4.2 `skills/orchestrate/`: `scripts/ask-coordinator.sh` writes one atomic `questions/.json` record per task and refuses a task name containing `/`, `.`, or `..`; `scripts/watch-status.sh` surfaces it as its own exit code within one poll; `scripts/send-prompt.sh keys` validates every key against the allowlist before sending any and sends one `send-keys` per key; `scripts/orca-worker-stalled.sh` documents the measurement behind the third state — three workers held a live PTY on an interactive prompt for 75 minutes with byte-identical diffs while every alive/dead check passed, and terminal-output timestamps were measured and rejected because a TUI's repaint keeps them fresh +- Field observation 2026-08-08 (dev-loop orchestrate, tmux worker `lo-4-qag1`): the worker raised a numbered chooser in its pane and sat 30 minutes past its silence threshold with the terminal alive. Two rounds of number-then-Enter cleared it (selection, then confirmation); the prompt queued in the input line before the chooser opened was never submitted, and the phase reached its next state only after that prompt was re-sent diff --git a/wiki/infrastructure/index.md b/wiki/infrastructure/index.md index 36a0771..65b36ca 100644 --- a/wiki/infrastructure/index.md +++ b/wiki/infrastructure/index.md @@ -16,6 +16,7 @@ Match your situation to a "load when" line; load only matching pages. | [shared-run-state](agent-orchestration/shared-run-state.md) | Several agent/worker sessions coordinate through files in one repository (status directory, briefs, escalations, claim files); choosing the path layout for that state; starting an orchestration in a repo that may already have one running; a watcher woke on a task id it did not create; the default branch moved during a run | | [pane-delivery-confirmation](agent-orchestration/pane-delivery-confirmation.md) | An orchestrator drives another program through a terminal multiplexer (`tmux send-keys` + `capture-pane`) and must decide whether the input was consumed, retry, or escalate; a pane diff is being used as delivery evidence; the target echoes but never runs the input | | [session-completion-gates](agent-orchestration/session-completion-gates.md) | Writing a Stop/completion hook that blocks a worker session from ending while its phase is non-terminal; the gate fires on a worker that followed its own prompt; deciding the terminal phase set, the unknown-phase default, and how the gate bounds its own repetition | +| [unattended-worker-questions](agent-orchestration/unattended-worker-questions.md) | A worker agent raises a question through its own interactive UI (a numbered chooser, a confirmation/trust/re-auth screen) with no human at that terminal; a worker is flagged stalled with a live terminal and no task-level error; a worker reports a decision it assumed rather than asked; designing the channel a worker uses to ask its coordinator for a decision | | [worktree-isolated-workers](agent-orchestration/worktree-isolated-workers.md) | Authoring the brief/output contract for parallel workers each confined to its own git worktree; workers stall at the same phase with no task-level error; deciding where shared or produced artifacts live and which direction (read vs write) a worktree guardrail stops | ## ci-cd