iceboundrock / iceboundrock/AutoForge

Executor: decide what happens to descendants that outlive the agent child

Open
#85 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
0
Avg merge
8h 56m
Merged PRs (30d)
40

Description

Follow-up from the review of #84 (finding P1) and #53.

Context

Since #84 (with the review fix), execute() treats an invocation as complete only when the child has exited and both of its pipes reached EOF, and the timeout bounds both together. That restores the pre-#53 communicate(timeout=...) contract: a descendant that inherited the agent's stdout/stderr (a dev server the agent started with &) keeps the pipes open, and at the timeout the whole process group is killed and the result is a timeout. A descendant that also left the group (setsid) is not waited for: the capture is abandoned after the kill grace.

Two policy questions were deliberately left out of that fix because they change orchestration semantics rather than restore them.

1. A pipe-holding descendant costs the full timeout and discards a good result

The agent exits 0 with a valid CONTROL_RESULT, but a leftover server holds the pipes. Today the controller waits the remaining timeout_seconds (up to 30 minutes with the default), then kills the group and reports timed out after Ns and was killed with exit_code = -1, so the child's real exit code and its result are lost, and the phase is treated as a timeout.

Alternative: once the child has exited, wait only a short grace for EOF, then kill the group, drain, and return the child's real exit code and output with a flag (for example descendants_killed) that the run log records. The engine would then parse the result normally; the block is still on stdout, though the tail may no longer end with it if the leftover wrote after the agent did.

Trade-off: faster and keeps the result, but it kills processes on the normal-exit path, which is a new policy (see 2), and the flag needs a place in execution.json / events.jsonl.

2. Descendants that do not hold the pipes linger after a normal exit

Pre-existing, unchanged by #53 or #84: the group is killed only on the timeout path. A background process the agent redirected to /dev/null or a file survives the invocation and the next phase runs next to it (ports held, files written into the worktree). The executor docstring promises that grandchildren "do not linger" only for the timeout case.

Options: kill the group at the end of every invocation (simple, deterministic, but forbids an agent from deliberately leaving a service running), or leave it to the operator (status quo), or make it a config knob under execution:.

3. Reporting

In case 1 the run log says the agent timed out although it exited. If the policy stays as it is, the ExecutionResult / run log could record that the child exited before the deadline and what held the invocation open, so the operator is pointed at the leftover rather than at a slow agent.

Where the behaviour is

  • src/autoforge/executor.py: execute(), _terminate_group(), _BoundedReader.abandon()
  • tests/test_executor.py: test_descendant_holding_the_pipe_is_bounded_by_the_timeout, test_descendant_outside_the_group_cannot_hold_the_capture_open
  • docs/agent-guides/architecture.md, executor section

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with execute(), _terminate_group(), and _BoundedReader.abandon() in src/autoforge/executor.py, then read the two descendant tests in tests/test_executor.py and the executor section of docs/agent-guides/architecture.md. Resolve and document the policy for pipe-holding and non-pipe-holding descendants, then update execution reporting and tests so the selected behavior and completion status are explicit.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.