From 49c054aaf9954e31a715aecae23b6c67269badb1 Mon Sep 17 00:00:00 2001 From: TolaMironcenko Date: Thu, 15 Oct 2026 01:45:17 +0700 Subject: [PATCH] S00-012: Record blocked task and remediation handoff Changes: Preserve incomplete work and blocker metadata for S00-012. This checkpoint does not mark implementation accepted. Validation: Session ended with status blocked. Blocker: Submit-transition descendant regression fails: repeated stop_process_tree after parent reap raises EPERM at os.killpg; launch OSError handling then attempts invalid escalation from review state. Task: S00-012 Agent: auto-ci-cd-28868645424b Role: ci-cd Action: claim Status: blocked Task title: Fix runner prompt delivery after partial stdin timeout --- planning/ROADMAP.md | 2 +- planning/TASK_MATRIX.md | 5 +- planning/TRACEABILITY.md | 2 +- planning/stages/S00.md | 3 +- planning/task_matrix.csv | 3 +- planning/tasks.json | 58 +++++++++++++++++- planning/tasks/S00-012.md | 2 +- planning/tasks/S00-014.md | 60 +++++++++++++++++++ state/blockers/S00-014.md | 22 +++++++ .../S00-012-auto-ci-cd-28868645424b.md | 29 +++++++++ state/handoffs/S00-012.md | 6 +- .../S00-012-auto-ci-cd-28868645424b.json | 30 ++++++++++ state/tasks.json | 50 +++++++++++++--- tests/tooling/test_automation.py | 43 +++++++++++++ 14 files changed, 295 insertions(+), 20 deletions(-) create mode 100644 planning/tasks/S00-014.md create mode 100644 state/blockers/S00-014.md create mode 100644 state/evidence/S00-012-auto-ci-cd-28868645424b.md create mode 100644 state/issues/S00-012-auto-ci-cd-28868645424b.json diff --git a/planning/ROADMAP.md b/planning/ROADMAP.md index 3b9fe30..34deb3f 100644 --- a/planning/ROADMAP.md +++ b/planning/ROADMAP.md @@ -6,7 +6,7 @@ Зафиксировать Web scope, browser targets и проверенные кандидаты, не устанавливая непроверенный framework по догадке. -Задач: 13; entry: нет; exit: S00-010. +Задач: 14; entry: нет; exit: S00-010. ## [S01: Предметные контракты](stages/S01.md) diff --git a/planning/TASK_MATRIX.md b/planning/TASK_MATRIX.md index 6a94c1f..9d3d78b 100644 --- a/planning/TASK_MATRIX.md +++ b/planning/TASK_MATRIX.md @@ -1,6 +1,6 @@ # Матрица задач -Generated; state revision **17**. Canonical status: state/tasks.json. +Generated; state revision **19**. Canonical status: state/tasks.json. | ID | Этап | Оператор | Reviewer | Статус | Owner | Зависимости | Задача | | --- | --- | --- | --- | --- | --- | --- | --- | @@ -14,8 +14,9 @@ Generated; state revision **17**. Canonical status: state/tasks.json. | [S00-008](tasks/S00-008.md) | S00 | ci-cd | qa | todo | | S00-003, S00-004 | Описать WSS/upload/TURN/push topology | | [S00-009](tasks/S00-009.md) | S00 | orchestrator | security | todo | | S00-003, S00-004, S00-005, S00-006, S00-007, S00-008 | Согласовать результаты spikes | | [S00-011](tasks/S00-011.md) | S00 | ci-cd | security | done | auto-ci-cd-d105e8027730 | S00-001 | Restore verified npm registry access for the stack spike | -| [S00-012](tasks/S00-012.md) | S00 | ci-cd | qa | todo | | S00-001, S00-011, S00-013 | Fix runner prompt delivery after partial stdin timeout | +| [S00-012](tasks/S00-012.md) | S00 | ci-cd | qa | blocked | auto-ci-cd-28868645424b | S00-001, S00-011, S00-013, S00-014 | Fix runner prompt delivery after partial stdin timeout | | [S00-013](tasks/S00-013.md) | S00 | ci-cd | qa | done | auto-ci-cd-5f68f03dd33b | S00-001, S00-011 | Bound oversized S21-006 runner context without truncating requirements | +| [S00-014](tasks/S00-014.md) | S00 | ci-cd | qa | todo | | S00-001, S00-011, S00-013 | Fix repeated runner cleanup after a submitted parent is reaped | | [S00-010](tasks/S00-010.md) | S00 | qa | orchestrator | todo | | S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009 | Gate: Профиль и проверка стека | | [S01-001](tasks/S01-001.md) | S01 | orchestrator | security | todo | | S00-010 | Описать identity/model contracts | | [S01-002](tasks/S01-002.md) | S01 | orchestrator | security | todo | | S00-010, S01-001 | Описать async account context | diff --git a/planning/TRACEABILITY.md b/planning/TRACEABILITY.md index db75c23..e806a5d 100644 --- a/planning/TRACEABILITY.md +++ b/planning/TRACEABILITY.md @@ -204,7 +204,7 @@ Allocated означает наличие плана/приёмки, а не р | NFR-004 | web | Web requirement; cross-platform clauses apply only in Web context. | S02-012, S09-012, S21-007 | | NFR-005 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-006, S02-012, S09-012, S20-006, S21-011 | | NFR-006 | web | Web requirement; cross-platform clauses apply only in Web context. | S02-012, S09-012 | -| NFR-007 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-002, S00-011, S00-012, S00-013, S02-001, S02-002, S09-012, S21-008, S21-009 | +| NFR-007 | web | Web requirement; cross-platform clauses apply only in Web context. | S00-002, S00-011, S00-012, S00-013, S00-014, S02-001, S02-002, S09-012, S21-008, S21-009 | | NFR-008 | web | Web requirement; cross-platform clauses apply only in Web context. | S02-004, S02-005, S02-006, S09-012, S21-009 | | NFR-009 | web | Web requirement; cross-platform clauses apply only in Web context. | S02-012, S09-012, S19-006, S20-003, S21-010 | | UI-001 | web | Web requirement; cross-platform clauses apply only in Web context. | S03-002, S20-001, S21-006 | diff --git a/planning/stages/S00.md b/planning/stages/S00.md index 1b323e3..9e99d2e 100644 --- a/planning/stages/S00.md +++ b/planning/stages/S00.md @@ -16,8 +16,9 @@ - [S00-008](../tasks/S00-008.md): Описать WSS/upload/TURN/push topology — ci-cd; todo. - [S00-009](../tasks/S00-009.md): Согласовать результаты spikes — orchestrator; todo. - [S00-011](../tasks/S00-011.md): Restore verified npm registry access for the stack spike — ci-cd; done. -- [S00-012](../tasks/S00-012.md): Fix runner prompt delivery after partial stdin timeout — ci-cd; todo. +- [S00-012](../tasks/S00-012.md): Fix runner prompt delivery after partial stdin timeout — ci-cd; blocked. - [S00-013](../tasks/S00-013.md): Bound oversized S21-006 runner context without truncating requirements — ci-cd; done. +- [S00-014](../tasks/S00-014.md): Fix repeated runner cleanup after a submitted parent is reaped — ci-cd; todo. - [S00-010](../tasks/S00-010.md): Gate: Профиль и проверка стека — qa; todo. ## Граница этапа diff --git a/planning/task_matrix.csv b/planning/task_matrix.csv index 869b5f4..dd51446 100644 --- a/planning/task_matrix.csv +++ b/planning/task_matrix.csv @@ -9,8 +9,9 @@ S00-007,S00,security,orchestrator,todo,,"S00-004, S00-005",Утвердить pa S00-008,S00,ci-cd,qa,todo,,"S00-003, S00-004",Описать WSS/upload/TURN/push topology S00-009,S00,orchestrator,security,todo,,"S00-003, S00-004, S00-005, S00-006, S00-007, S00-008",Согласовать результаты spikes S00-011,S00,ci-cd,security,done,auto-ci-cd-d105e8027730,S00-001,Restore verified npm registry access for the stack spike -S00-012,S00,ci-cd,qa,todo,,"S00-001, S00-011, S00-013",Fix runner prompt delivery after partial stdin timeout +S00-012,S00,ci-cd,qa,blocked,auto-ci-cd-28868645424b,"S00-001, S00-011, S00-013, S00-014",Fix runner prompt delivery after partial stdin timeout S00-013,S00,ci-cd,qa,done,auto-ci-cd-5f68f03dd33b,"S00-001, S00-011",Bound oversized S21-006 runner context without truncating requirements +S00-014,S00,ci-cd,qa,todo,,"S00-001, S00-011, S00-013",Fix repeated runner cleanup after a submitted parent is reaped S00-010,S00,qa,orchestrator,todo,,"S00-001, S00-002, S00-003, S00-004, S00-005, S00-006, S00-007, S00-008, S00-009",Gate: Профиль и проверка стека S01-001,S01,orchestrator,security,todo,,S00-010,Описать identity/model contracts S01-002,S01,orchestrator,security,todo,,"S00-010, S01-001",Описать async account context diff --git a/planning/tasks.json b/planning/tasks.json index f48a550..00f8d02 100644 --- a/planning/tasks.json +++ b/planning/tasks.json @@ -685,7 +685,8 @@ "depends_on": [ "S00-001", "S00-011", - "S00-013" + "S00-013", + "S00-014" ], "requirements": [ "NFR-007" @@ -777,6 +778,61 @@ ], "context_budget_chars": 48000 }, + { + "id": "S00-014", + "stage": "S00", + "kind": "blocker", + "root_task": "S00-002", + "blocker_depth": 2, + "unblocks": [ + "S00-012" + ], + "role": "ci-cd", + "reviewer_role": "qa", + "title": "Fix repeated runner cleanup after a submitted parent is reaped", + "outcome": "Reliable repeated lifecycle cleanup after submit with a reaped parent and SIGTERM-ignoring descendant, preserving actual process-tree termination and valid workflow state.", + "depends_on": [ + "S00-001", + "S00-011", + "S00-013" + ], + "requirements": [ + "NFR-007" + ], + "scope": [ + "scripts/runner.py", + "tests/tooling/test_automation.py" + ], + "inputs": [ + "docs/WEB_PROFILE.md", + "docs/ARCHITECTURE.md", + "docs/CONTRACTS.md", + "docs/TESTING.md", + "roles/orchestrator.md", + "docs/decisions/README.md", + "state/blockers/S00-012.md", + "state/blockers/S00-014.md" + ], + "spec_sections": [], + "ui_sections": [], + "steps": [ + "Read S00-012 evidence and preserved descendant regressions.", + "Reproduce repeated cleanup EPERM in the supplied execution harness without launching a model.", + "Correct only the repeated-cleanup lifecycle failure; retain fail-closed handling for inaccessible live descendants and terminal/deadline monitoring.", + "Run descendant, delayed stdin and existing lifecycle checks plus make check; record evidence and submit." + ], + "acceptance": [ + "Submit-transition descendant regression completes without invalid escalation or delayed source writes.", + "Timeout and terminal-transition paths terminate descendants, including SIGTERM-ignoring children.", + "Repeated cleanup does not hide a failure to terminate a live process; stdin delivery and prompt budgets remain intact." + ], + "checks": [ + "Both preserved descendant regressions.", + "Delayed-reader UTF-8/EOF, timeout, transition, scope and fresh-session runner checks.", + "make check" + ], + "context_budget_chars": 48000 + }, { "id": "S00-010", "stage": "S00", diff --git a/planning/tasks/S00-012.md b/planning/tasks/S00-012.md index bfaa20c..6c706cc 100644 --- a/planning/tasks/S00-012.md +++ b/planning/tasks/S00-012.md @@ -7,7 +7,7 @@ - Этап: S00 - Оператор: ci-cd - Reviewer: qa -- Зависимости: S00-001, S00-011, S00-013 +- Зависимости: S00-001, S00-011, S00-013, S00-014 - Требования: NFR-007 ## Один результат diff --git a/planning/tasks/S00-014.md b/planning/tasks/S00-014.md new file mode 100644 index 0000000..94dcff7 --- /dev/null +++ b/planning/tasks/S00-014.md @@ -0,0 +1,60 @@ +# S00-014: Fix repeated runner cleanup after a submitted parent is reaped + +- Remediation для: S00-012; root: S00-002; depth: 2 + +> Generated from planning/tasks.json; status is in state/tasks.json. + +- Этап: S00 +- Оператор: ci-cd +- Reviewer: qa +- Зависимости: S00-001, S00-011, S00-013 +- Требования: NFR-007 + +## Один результат + +Reliable repeated lifecycle cleanup after submit with a reaped parent and SIGTERM-ignoring descendant, preserving actual process-tree termination and valid workflow state. + +## Разрешённые пути + +- `scripts/runner.py` +- `tests/tooling/test_automation.py` + +Не изменять другие modules, shared contracts или spec snapshots без изменения плана. Stem без расширения разрешает принятые stack-specific extensions и focused test рядом. + +## Прочитать + +- docs/WEB_PROFILE.md +- docs/ARCHITECTURE.md +- docs/CONTRACTS.md +- docs/TESTING.md +- roles/orchestrator.md +- docs/decisions/README.md +- state/blockers/S00-012.md +- state/blockers/S00-014.md + +## Шаги + +1. Read S00-012 evidence and preserved descendant regressions. +2. Reproduce repeated cleanup EPERM in the supplied execution harness without launching a model. +3. Correct only the repeated-cleanup lifecycle failure; retain fail-closed handling for inaccessible live descendants and terminal/deadline monitoring. +4. Run descendant, delayed stdin and existing lifecycle checks plus make check; record evidence and submit. + +## Приёмка + +1. Submit-transition descendant regression completes without invalid escalation or delayed source writes. +2. Timeout and terminal-transition paths terminate descendants, including SIGTERM-ignoring children. +3. Repeated cleanup does not hide a failure to terminate a live process; stdin delivery and prompt budgets remain intact. + +## Focused checks + +1. Both preserved descendant regressions. +2. Delayed-reader UTF-8/EOF, timeout, transition, scope and fresh-session runner checks. +3. make check + +## Блокер и завершение запуска + +Для всех ролей scope — только эта задача. При блокере создать issue JSON по state/ISSUE_TEMPLATE.json, вызвать escalate с текущим ID/role/agent, проверить status=blocked и resolution_task, затем немедленно завершить запуск. Не решать blocker и не выбирать следующую задачу самому. Новый агент назначается runner. Правки metadata через CLI — единственное исключение scope. + +## Передача + +Сохранить evidence/handoff; submit → review и завершить запуск. Reviewer также выполняет только эту задачу, включая обязательное escalate при блокере. diff --git a/state/blockers/S00-014.md b/state/blockers/S00-014.md new file mode 100644 index 0000000..a0923de --- /dev/null +++ b/state/blockers/S00-014.md @@ -0,0 +1,22 @@ +# Blocker S00-014 + +- Original task: S00-012 +- Root task: S00-002 +- Reporter: auto-ci-cd-28868645424b +- Role: ci-cd +- Original owner: auto-ci-cd-28868645424b +- Waits for user/external condition: False + +## Cause + +Submit-transition descendant regression fails: repeated stop_process_tree after parent reap raises EPERM at os.killpg; launch OSError handling then attempts invalid escalation from review state. + +## One remediation outcome + +Reliable repeated lifecycle cleanup after submit with a reaped parent and SIGTERM-ignoring descendant, preserving actual process-tree termination and valid workflow state. + +## Evidence / reproduction + +python3 -m unittest discover -s tests/tooling -p test_automation.py -v; test_submit_transition_stops_source_writing_descendant errors. In-memory trace: first cleanup returns parent -15; repeated cleanup raises PermissionError at runner.py:340. Evidence: state/evidence/S00-012-auto-ci-cd-28868645424b.md + +The reporting agent must stop now. A new agent implements only S00-014. diff --git a/state/evidence/S00-012-auto-ci-cd-28868645424b.md b/state/evidence/S00-012-auto-ci-cd-28868645424b.md new file mode 100644 index 0000000..0c47a68 --- /dev/null +++ b/state/evidence/S00-012-auto-ci-cd-28868645424b.md @@ -0,0 +1,29 @@ +# S00-012 executor blocker evidence + +Agent: auto-ci-cd-28868645424b; role: ci-cd; date: 2026-10-15. +No submission or acceptance is claimed. + +Input: assigned card/packet, startup instructions, prior partial handoff and diagnostic evidence, exact NFR-007, accepted scope ADR, S00-001/S00-011/S00-013 dependency evidence/reviews/handoffs. Output attempted: complete stdin delivery with verified lifecycle cleanup. + +## Preserved implementation and current changes + +The checkpoint c28412a already contains the stdin correction and delayed-reader regression. It supplies the persisted binary UTF-8 prompt file as stdin, polls wait at .2-second intervals, and retains deadlines/terminal-transition/process-group cleanup. S00-013 subsequently corrected prompt budgeting independently. No runner source changes were made in this session. + +Added two real subprocess regressions in tests/tooling/test_automation.py. A descendant installs SIGTERM ignore, records readiness, then attempts a delayed source write. The parent either times out or submits and remains alive. Tests require cleanup to prevent the write. These tests are preserved as partial work; the submit-transition test does not pass. + +## Actual commands/results + +- tasks.py resume/show/packet: exit 0 each; S00-012 already owned, no repeated claim. +- git status --short at entry: exit 0; only coordinator state/tasks.json claim metadata modified. +- git log for S00-012 and git show c28412a scoped source: exit 0; prior checkpoint inspected. +- Synthetic legacy transport reproduction: exit 0; Python 3.9.6, 140000 UTF-8 bytes, .5-second delayed reader, communicate(payload, timeout=.2) then communicate(None, timeout=1) both time out. Child killed/reaped in finally. +- python3 -m unittest discover -s tests/tooling -p test_automation.py -v: exit 1; 26 tests in 9.489s, 25 passed, submit descendant test errored. Complete 140024-byte delayed UTF-8 prompt/EOF, timeout descendant, fresh-session chain, scope, escalation transition and both prompt-budget regressions passed. +- Isolated RunnerTests._check_descendant_cleanup(True) invocation: exit 1; same error reproduced. +- Same isolated invocation with an in-memory tracing wrapper around stop_process_tree: exit 1; first stop_process_tree succeeded and parent returncode was -15; second invocation with parent already reaped raised PermissionError [Errno 1] Operation not permitted at runner.py:340, os.killpg(process.pid, SIGTERM). No persistent tracing/source change. +- git diff --check and git diff --stat: exit 0; only tests/tooling/test_automation.py plus coordinator state metadata changed. + +## Blocker and limits + +After submit, stop_process_tree runs during transition handling and again in finally. With a SIGTERM-ignoring descendant and reaped parent, the second process-group signal is denied in this managed execution environment. The broad launch OSError handler then treats this as executable startup failure; escalation from an already submitted executor raises ValueError: Only current executor or assigned-role reviewer may escalate its current task. Timeout descendant test passes; transition descendant cleanup cannot be declared passed. The precise sandbox/OS policy causing EPERM is not proven beyond the observed syscall result. + +Stop source edits and remediate this one lifecycle failure in a new session. Preserve real descendant termination, deadline/transition monitoring and fail-closed behavior for inaccessible live processes; do not simply suppress permission errors. make check was not run after establishing the blocker, and the automation suite is not passed. No actual model, product/provider integration, Git mutation, immutable spec or shared-contract change occurred. diff --git a/state/handoffs/S00-012.md b/state/handoffs/S00-012.md index 10f5bc7..88c74bf 100644 --- a/state/handoffs/S00-012.md +++ b/state/handoffs/S00-012.md @@ -1,7 +1,7 @@ # S00-012 partial handoff -Executor: manual-ci-cd-stdin-20261015b, ci-cd. Partial stdin transport fix and regression test are in scripts/runner.py and tests/tooling/test_automation.py. New delayed UTF-8 reader test failed before the fix and passed after it. Existing timeout/terminal-transition tests pass. No acceptance/submission is claimed. +Executor: auto-ci-cd-28868645424b, ci-cd. Existing stdin fix and delayed UTF-8 regression from checkpoint c28412a were inspected. Complete 140024-byte delivery/EOF and current prompt budgets pass. No runner source changes this session. -Blocker: the existing all-prompts budget test fails because S21-006 prompt exceeds even the 90000-character diagnostic maximum. Separate context-budget remediation is required; it must retain complete exact task requirements and bounded relevant inputs, without increasing limits beyond contract or suppressing validation. Evidence: state/evidence/S00-012-manual-ci-cd-stdin-20261015b.md. +Added two descendant cleanup regressions in tests/tooling/test_automation.py; timeout scenario passes, submit-transition scenario errors. A SIGTERM-ignoring descendant records readiness and would write a source file after 1.5 seconds. Parent submits and sleeps. First stop_process_tree succeeds; its repeated finally invocation after parent is reaped (-15) raises EPERM at os.killpg(SIGTERM). Broad OSError handling then tries invalid escalation from review state. No acceptance or submission claimed. -After reviewed remediation, a fresh S00-012 executor should inspect the preserved diff, rerun regression and make check, write evidence and commit message, then submit. Coordinator must checkpoint the preserved partial work and pending prior blocker metadata before any automated new agent; current checkout is dirty. Current reporter ends after escalate and cannot continue remediation. +Evidence: state/evidence/S00-012-auto-ci-cd-28868645424b.md. Full automation run: 25/26 passed, exit 1. make check not run following this blocker. Next fresh remediation must resolve this bounded repeated-cleanup lifecycle failure without weakening process-tree termination or suppressing real live-process permission failures. After independently reviewed remediation, a fresh S00-012 executor must rerun regressions/make check and submit. Coordinator owns checkpoint; this reporter stops after escalate. diff --git a/state/issues/S00-012-auto-ci-cd-28868645424b.json b/state/issues/S00-012-auto-ci-cd-28868645424b.json new file mode 100644 index 0000000..105c725 --- /dev/null +++ b/state/issues/S00-012-auto-ci-cd-28868645424b.json @@ -0,0 +1,30 @@ +{ + "title": "Fix repeated runner cleanup after a submitted parent is reaped", + "reason": "Submit-transition descendant regression fails: repeated stop_process_tree after parent reap raises EPERM at os.killpg; launch OSError handling then attempts invalid escalation from review state.", + "reproduction": "python3 -m unittest discover -s tests/tooling -p test_automation.py -v; test_submit_transition_stops_source_writing_descendant errors. In-memory trace: first cleanup returns parent -15; repeated cleanup raises PermissionError at runner.py:340. Evidence: state/evidence/S00-012-auto-ci-cd-28868645424b.md", + "role": "ci-cd", + "reviewer_role": "qa", + "scope": [ + "scripts/runner.py", + "tests/tooling/test_automation.py" + ], + "outcome": "Reliable repeated lifecycle cleanup after submit with a reaped parent and SIGTERM-ignoring descendant, preserving actual process-tree termination and valid workflow state.", + "steps": [ + "Read S00-012 evidence and preserved descendant regressions.", + "Reproduce repeated cleanup EPERM in the supplied execution harness without launching a model.", + "Correct only the repeated-cleanup lifecycle failure; retain fail-closed handling for inaccessible live descendants and terminal/deadline monitoring.", + "Run descendant, delayed stdin and existing lifecycle checks plus make check; record evidence and submit." + ], + "acceptance": [ + "Submit-transition descendant regression completes without invalid escalation or delayed source writes.", + "Timeout and terminal-transition paths terminate descendants, including SIGTERM-ignoring children.", + "Repeated cleanup does not hide a failure to terminate a live process; stdin delivery and prompt budgets remain intact." + ], + "checks": [ + "Both preserved descendant regressions.", + "Delayed-reader UTF-8/EOF, timeout, transition, scope and fresh-session runner checks.", + "make check" + ], + "depends_on": [], + "requires_user_input": false +} diff --git a/state/tasks.json b/state/tasks.json index c25d5a3..5cc3768 100644 --- a/state/tasks.json +++ b/state/tasks.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "revision": 17, + "revision": 19, "tasks": { "S00-001": { "status": "done", @@ -1136,15 +1136,17 @@ "completed_at": "2026-10-14T18:11:33+00:00" }, "S00-012": { - "status": "todo", - "owner": null, + "status": "blocked", + "owner": "auto-ci-cd-28868645424b", "external_wait": false, - "reason": null, - "started_at": "2026-10-14T18:33:49+00:00", - "updated_at": "2026-10-14T18:42:03+00:00", - "blocked_by": [], + "reason": "Submit-transition descendant regression fails: repeated stop_process_tree after parent reap raises EPERM at os.killpg; launch OSError handling then attempts invalid escalation from review state.", + "started_at": "2026-10-14T18:42:03+00:00", + "updated_at": "2026-10-14T18:45:16+00:00", + "blocked_by": [ + "S00-014" + ], "resume_status": "in_progress", - "blocker_report": "state/blockers/S00-013.md", + "blocker_report": "state/blockers/S00-014.md", "handoff": "state/handoffs/S00-012.md", "previous_owner": "manual-ci-cd-stdin-20261015b", "resumed_after_blocker": true @@ -1161,6 +1163,12 @@ "reviewer": "auto-qa-869b22acd478", "review_evidence": "state/evidence/S00-013-review.md", "completed_at": "2026-10-14T18:42:03+00:00" + }, + "S00-014": { + "status": "todo", + "owner": null, + "external_wait": false, + "reason": null } }, "events": [ @@ -1375,11 +1383,35 @@ "to": "done", "reason": null, "evidence": "state/evidence/S00-013-review.md" + }, + { + "revision": 18, + "at": "2026-10-14T18:42:03+00:00", + "action": "claim", + "task": "S00-012", + "agent": "auto-ci-cd-28868645424b", + "role": "ci-cd", + "from": "todo", + "to": "in_progress", + "reason": null + }, + { + "revision": 19, + "at": "2026-10-14T18:45:16+00:00", + "action": "escalate", + "task": "S00-012", + "resolution_task": "S00-014", + "agent": "auto-ci-cd-28868645424b", + "role": "ci-cd", + "from": "in_progress", + "to": "blocked", + "reason": "Submit-transition descendant regression fails: repeated stop_process_tree after parent reap raises EPERM at os.killpg; launch OSError handling then attempts invalid escalation from review state." } ], "retired_agents": [ "auto-orchestrator-3a4f07103316", "manual-security-stdin-20261015a", - "manual-ci-cd-stdin-20261015b" + "manual-ci-cd-stdin-20261015b", + "auto-ci-cd-28868645424b" ] } diff --git a/tests/tooling/test_automation.py b/tests/tooling/test_automation.py index c1a90aa..f915443 100644 --- a/tests/tooling/test_automation.py +++ b/tests/tooling/test_automation.py @@ -276,6 +276,49 @@ else: self.assertEqual(result['stop'], 'session_limit') self.assertEqual(self.tracker.state()['tasks']['S00-001']['status'], 'blocked') + def _check_descendant_cleanup(self, transition): + import time + ready = self.root / 'state/descendant-ready' + late_write = self.root / 'src/late-descendant-write.txt' + child_code = ( + "import pathlib,signal,time;signal.signal(signal.SIGTERM,signal.SIG_IGN);" + f"pathlib.Path({str(ready)!r}).write_text('ready');" + "time.sleep(1.5);" + f"pathlib.Path({str(late_write)!r}).write_text('unexpected')" + ) + startup = ( + "import subprocess,time\n" + f"subprocess.Popen([sys.executable,'-c',{child_code!r}])\n" + f"while not pathlib.Path({str(ready)!r}).exists():time.sleep(.01)\n" + ) + fake = self.root / 'fake_agent.py' + source = fake.read_text().replace( + "prompt=sys.stdin.read();assert 'fresh session' in prompt", + startup + ("prompt=sys.stdin.read();assert 'fresh session' in prompt" + if transition else "time.sleep(10)")) + fake.write_text(source + '\nimport time;time.sleep(10)\n') + (self.root / 'state/first-blocker').write_text('skip fixture blocker') + runner = RUN_MODULE.Runner(self.root, dict(self.config, max_sessions=1, + timeout_seconds=2 if transition else .5)) + result = runner.run() + self.assertEqual(result['launched'], 1) + self.assertTrue(ready.is_file(), 'Descendant must start before cleanup') + record = json.loads(next((self.root / 'state/runs').glob('*/run.json')).read_text()) + self.assertEqual(record['stopped_after_transition'], transition) + self.assertEqual(self.tracker.state()['tasks']['S00-001']['status'], + 'review' if transition else 'blocked') + time.sleep(1.6) + self.assertFalse(late_write.exists(), 'Descendant survived process-group cleanup') + self.assertEqual(record['scope_violations'], []) + + @unittest.skipUnless(sys.platform != 'win32', 'POSIX process-group cleanup') + def test_timeout_stops_source_writing_descendant(self): + self._check_descendant_cleanup(transition=False) + + @unittest.skipUnless(sys.platform != 'win32', 'POSIX process-group cleanup') + def test_submit_transition_stops_source_writing_descendant(self): + self._check_descendant_cleanup(transition=True) + def test_scope_matcher_checks_modified_created_deleted_files(self): self.assertEqual(RUN_MODULE.scope_violations({'a': 'old', 'gone': 'old'}, {'a': 'new', 'created': 'new'}, ['a']), ['created', 'gone'])