Stamp the project pointer by the door's own child predicate; say what the timeout kill reaches

Two advisory findings of the panel's second reviewer:

- project_journal stamped the last-result pointer for any task without a
  parent_task_id, while the promote door calls a row a child by its parent OR
  by its subagent role. One predicate now decides both the stamp and the
  location mirror, so a role-only child cannot move the room's pointer.
- The run_command TOOL_TIMEOUT text said the subprocess tree was terminated.
  The schema in this PR already states the measured truth (a child detached
  with & is reparented and survives); the refusal text now says the process
  group was killed and a detached child may survive untracked.
This commit is contained in:
Ouroboros 2026-09-21 14:32:01 +03:00
parent 3837e384fd
commit 86a920aa6c
3 changed files with 12 additions and 3 deletions

View file

@ -226,7 +226,9 @@ def record_task_finalization(
)
except Exception:
log.debug("project journal task-done entry failed", exc_info=True)
if not str(task.get("parent_task_id") or "").strip():
is_root = not str(task.get("parent_task_id") or "").strip() and str(
task.get("delegation_role") or "") != "subagent" # the door's own child predicate
if is_root:
# The pointer answers "continue from here" for the ROOM, so only a ROOT may
# stamp it: a child finalizing after its root moved the room's single
# candidate onto work no owner ever addressed, and the room was then left
@ -237,7 +239,7 @@ def record_task_finalization(
_record_work_location(project_id, task)
except Exception:
log.debug("project journal work-location entry failed", exc_info=True)
if not str(task.get("parent_task_id") or "").strip():
if is_root:
try:
mirror_tree_coordination_to_journal(
project_id, str(task.get("root_task_id") or tid), task_id=tid,

View file

@ -532,7 +532,7 @@ def _run_shell(
_record_scratch_fingerprints(ctx, scratch_abs)
return (
f"⚠️ TOOL_TIMEOUT (run_command): command exceeded the per-command timeout of {timeout_sec}s "
f"and its subprocess tree was terminated (root={binding.root}, cwd={work_dir}). NOTE: this is the per-command "
f"and its process group was killed; a child it detached may survive untracked (root={binding.root}, cwd={work_dir}). NOTE: this is the per-command "
f"FOREGROUND timeout, NOT the task deadline. For genuinely long-running compute (training, "
f"sampling, large builds/downloads), start it with start_service and poll "
f"service_status/service_logs while you do other work, or pass an explicit timeout_sec=<seconds> "

View file

@ -286,6 +286,13 @@ def test_only_a_root_finalization_moves_the_projects_pointer(tmp_path):
)
assert get_project(tmp_path, "racer")["last_task_result_id"] == "racer-root"
# The door calls a row a child by its parent OR by its role; so does the stamp.
record_task_finalization(
"racer", {"id": "racer-role-only", "root_task_id": "racer-root", "delegation_role": "subagent"},
objective="helper with no parent field", kind="task", exec_status="completed", drive_root=tmp_path,
)
assert get_project(tmp_path, "racer")["last_task_result_id"] == "racer-root"
def test_the_self_heal_scan_never_offers_or_stamps_a_child(tmp_path):
"""The lookup's fallback scan is the pointer's SECOND writer: with no pointer