name: project-agent-call-liveness-brd-written description: BRD for "agent call timeout must be liveness-based, not fixed-duration" written 2026-08-13; call-site inventory and open questions for SDD stage metadata:
type: project
BRD written 2026-08-13 at docs/todo/agent-call-liveness-not-fixed-duration-timeout-brd.md,
based on requirements doc docs/todo/agent-call-liveness-not-fixed-duration-timeout-requirements.md.
Triggered by a real incident: task bfd3ee82's Validator planning call (large embedded SDD/PRD
prompt) hit the 300s fixed timeout in trigger_org_node_structured and was misclassified as
blocked_reason='execution_error' via scheduler.py's catch-all (not a real hang).
Why: this closes the gap already flagged in
[feedback_agent_call_liveness_not_fixed_timeout] —
the "no fixed-duration timeout" rule had been agreed before but never implemented; bfd3ee82 is
the first real incident it caused, not the first time the rule was stated.
How to apply (facts verified 2026-08-13, re-check before trusting long-term):
- Only
e2e_pipeline.py:1131(run_test_script_for_real) catchessubprocess.TimeoutExpiredspecifically — everywhere else it falls through to theexecution_errorcatch-all (task_execution.py::_mark_blockedline 223,scheduler.pyline 255-256). - Full call-site inventory with fixed
timeout=values (300/600/1200/180 etc, all fixed-duration wall-clock):org_node_trigger.py(the two entry points),e2e_pipeline.py(plan/review/ implement/validate, several call sites),work_graph_plan.py::plan_work_graph,work_graph_orchestrate.py(judgment/reflection/skill-fix, several),org_level_loop.py:: run_fix_loop,root_cause_trace.py::real_validator_perspective,org_node_lifecycle.py:: trigger_org_node_full,work_graph_execute.py::execute_work_graph(separate — Dynamic Workflow script exec, not a directclaude -pcall, scoped as an open question not pre-included). scheduler.py::_BLOCKED_REASON_FOR_EXCEPTION(line 82-89) is the existing exception-type → blocked_reason registry to extend with a new "real stall" exception type →agent_call_stalled, rather than inventing a parallel routing mechanism.schema.py'sblocked_reasoncolumn is unconstrained TEXT (no CHECK), andfrontend/app.jsonly escapes/displays the raw string generically (no hardcoded enum switch beyonduser_paused/user_stopped) — addingagent_call_stalledneeds no schema migration and no frontend enum sync, unlike the drift pattern in [[project_task_status_enum_drift_gap]].- BRD deliberately left the core technical question open for SDD: what "liveness signal" is even
observable, given
claude -p --output-format jsonis one-shot, not streaming (needs real research, not an assumption) — see BRD's 阻塞未知/open-questions section before writing PRD/SDD. - Related but independent Goal:
docs/todo/boss-agent-autonomous-blocked-task-arbiter- requirements.md(handles what to do once a task IS truly stuck in blocked_pending_human) — this BRD's fix should land first to reduce false-positive noise Boss Agent would otherwise have to triage.