| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- """The resurrect bundle (goal 8 task 4): standalone (no-project) tasks
- and comment-resurrected terminal items.
- - A task created with project_id 0 dispatches with EMPTY co-developed
- and reference arrays, the "standalone" project name, and completes on
- its completion report.
- - A human comment on a TERMINAL goal (complete) re-opens the goal, its
- run task returns to suspended-offerable, and the resuming assignment
- carries the comment + the re-open line in its resume notice.
- - A human comment on a TERMINAL plain task re-queues it, the next
- assignment carries the comment.
- - A terminal goal-owned WORKER task keeps comments closed (the page
- hides the composer; the service path is the goal's alone).
- """
- from harness import * # noqa: F401,F403 — the shared wire helpers
- def run(ctx):
- auth, fake, fake_id, fake_token = ctx.auth, ctx.fake, ctx.fake_id, ctx.fake_token
- def create_goal(fields):
- act(auth, slot_public(auth, "/goals", "goals")["create"], fields)
- rows = [g for g in slot_public(auth, "/goals", "goals")["goals"]
- if g["title"] == fields["title"]]
- return int(rows[0]["id"])
- def run_task_of(goal_id):
- conn = db()
- try:
- row = conn.execute(
- "select id from tasks where goal_id = ? and kind = 'goal_run'",
- (goal_id,)).fetchone()
- return int(row[0]) if row else None
- finally:
- conn.close()
- print("== standalone task: created with no project, dispatched, done ==")
- state = slot_public(auth, "/tasks", "tasks")
- act(auth, state["create"], {
- "project_id": "0",
- "title": "Standalone research",
- "description": "Summarise the fleet's flaky tests.",
- "priority": "3",
- })
- standalone = task_id_of("Standalone research")
- detail = task_state(auth, standalone)
- check(detail["status"] == "draft" and int(detail["project_id"]) == 0,
- "a project_id 0 task creates in draft (project_id %s)" % detail["project_id"])
- page = http_get_page(auth, "/tasks/%d" % standalone)
- # Goal 41 T5: the context line is the breadcrumb trail now; a
- # standalone task carries NO project crumb (and no project link).
- crumbs = detail.get("crumbs", [])
- check(len(crumbs) == 2 and crumbs[0]["label"] == "Tasks"
- and crumbs[1]["href"] is None
- and "#%d " % standalone in crumbs[1]["label"],
- "a standalone task's crumbs are Tasks / #id (no project crumb): %r" % crumbs)
- check('class="breadcrumb"' in page and "/projects/" not in page,
- "the task page renders the breadcrumb trail, not a project link")
- check("(standalone)" in http_get_page(auth, "/tasks"),
- "the tasks list still marks the standalone task")
- check("No project (standalone)" in http_get_page(auth, "/tasks"),
- "the create form offers the No project (standalone) option")
- enqueue_task(auth, standalone)
- check(wait_for(lambda: len(fake.start_payloads) > 0 or False,
- timeout=30, what="standalone /start push") is not None,
- "the dispatcher pushes the standalone task to the fake saddle")
- payload = fake.start_payloads[-1]
- task_obj = payload.get("task") or {}
- check(task_obj.get("project_name") == "standalone",
- "the standalone assignment names the project 'standalone' (%s)"
- % task_obj.get("project_name"))
- check(task_obj.get("co_developed") == [] and task_obj.get("reference") == [],
- "the standalone assignment ships EMPTY co-developed and reference arrays")
- check(task_obj.get("branch_from", "x") == "",
- "the standalone assignment carries no branch_from")
- check(wait_task_done(auth, standalone) is not None,
- "the standalone task completes on its report")
- print("== terminal plain task: a comment re-queues it ==")
- plain = create_queued(auth, {
- "project_id": "1", "title": "Resurrect me",
- "description": "A plain project task that finishes.", "priority": "4"})
- check(wait_task_done(auth, plain) is not None, "the plain task completes")
- detail = task_state(auth, plain)
- act(auth, detail["comment"], {"body": "Please also cover the retry path."})
- detail = task_state(auth, plain)
- check(detail["status"] == "queued",
- "the comment re-queued the terminal plain task (%s)" % detail["status"])
- check(any("cover the retry path" in c["body"] for c in detail["comments"]),
- "the resurrecting comment rides the thread")
- conn = db()
- summary_kept = conn.execute(
- "select summary from tasks where id = ?", (plain,)).fetchone()[0]
- conn.close()
- check(summary_kept and len(summary_kept) > 0,
- "the earlier round's completion summary survives the re-open")
- check(wait_for(lambda: len(fake.start_payloads) > 1 or False,
- timeout=30, what="requeued dispatch") is not None,
- "the re-queued task dispatches again")
- def comment_reached_agent():
- for payload in fake.start_payloads:
- task_obj = payload.get("task") or {}
- if task_obj.get("id") == plain and any(
- "cover the retry path" in c["body"]
- for c in task_obj.get("comments", [])):
- return True
- return any("cover the retry path" in (c.get("text") or "")
- for c in fake.comment_log)
- # The comment reaches the agent by EITHER channel: inside an
- # assignment payload, or via the live /task-update push to the
- # RUNNING daemon (the delivered flag) — the dispatcher tick races
- # the dispatch, so wait for whichever lands.
- check(wait_for(comment_reached_agent, timeout=30,
- what="comment delivery") is not None,
- "the second round receives the resurrecting comment (assignment or live push)")
- check(wait_task_done(auth, plain) is not None, "the second round completes")
- print("== terminal goal: a comment re-opens it and resumes the agent ==")
- # One behaviour per ROUND: round 1 plans (parks blocked), round 2
- # (the approved resume) suspends, round 3 (the force-woke resume)
- # submits the completion report.
- fake.goal_script = [("plan", "# Resurrect plan\n\n1. Finish quickly"),
- ("suspend",),
- ("done", "# Completion\n\nThe report stands.")]
- goal = create_goal({"project_id": "1", "title": "Resurrect goal",
- "brief": "Completes, then re-opens on a comment.",
- "branch_name": "goal/resurrect"})
- # (Goal 27 refinements — the parking guard: the round-2 suspend
- # needs a live wake source under the goal.)
- conn = db()
- conn.execute("insert into tasks (project_id, goal_id, kind, title, status,"
- " priority, mode, creator, created_at) values (1, ?, 'task',"
- " 'Resurrect live worker', 'blocked', 5, 'implement', 'goal',"
- " strftime('%s','now'))", (goal,))
- conn.commit()
- conn.close()
- act(auth, goal_state(goal)["start"], {})
- check(wait_for(lambda: run_task_of(goal) is not None or False,
- timeout=30, what="goal run task appears") is not None,
- "starting the goal creates its run task")
- run_task = run_task_of(goal)
- check(wait_for(lambda: goal_state(goal)["status"] == "plan_review" or False,
- timeout=90, what="goal plans") is not None,
- "the goal reaches plan review")
- pending = goal_state(goal)["plan_pending_block"]
- act(auth, pending["answer_action"], {"verdict": "accept"})
- check(wait_for(lambda: goal_state(goal)["status"] == "active" or False,
- timeout=60, what="plan approved") is not None,
- "approving the plan activates the goal")
- check(wait_for(lambda: task_state(auth, run_task)["status"] == "suspended" or False,
- timeout=60, what="agent parks") is not None,
- "the agent parks after the plan")
- # Round 3 needs a wake: force-wake the parked agent so its scripted
- # done round (the completion report) runs.
- state = goal_state(goal)
- act(auth, state["force_wake"], {})
- # The completion round: the scripted done parks the run for review.
- check(wait_for(lambda: goal_state(goal)["status"] == "completion_review" or False,
- timeout=90, what="completion review opens") is not None,
- "the scripted done round enters completion review")
- block = goal_state(goal)["completion_pending_block"]
- act(auth, block["answer_action"], {"verdict": "accept"})
- check(wait_for(lambda: goal_state(goal)["status"] == "complete" or False,
- timeout=30, what="goal completes") is not None,
- "accepting the completion completes the goal")
- check(wait_for(lambda: task_state(auth, run_task)["status"] == "done" or False,
- timeout=30, what="run task done") is not None,
- "the run task closed done with the goal")
- goal_page = http_get_page(auth, "/goals/%d" % goal)
- check("stm-action=\"goal.comment\"" in goal_page,
- "the terminal goal page keeps the comment composer open")
- check("commenting re-opens it" in goal_page,
- "the composer explains the resurrect semantics on a terminal goal")
- state = goal_state(goal)
- act(auth, state["comment"], {"body": "One more sweep of the edge cases, please."})
- check(wait_for(lambda: goal_state(goal)["status"] == "active" or False,
- timeout=30, what="goal re-opens") is not None,
- "the comment re-opened the completed goal")
- check(wait_for(lambda: task_state(auth, run_task)["status"] == "suspended" or False,
- timeout=30, what="run re-offerable") is not None,
- "the DONE run task returned to suspended (the parked-resume shape)")
- conn = db()
- report_kept = conn.execute(
- "select completion_report from goals where id = ?", (goal,)).fetchone()[0]
- seeded = conn.execute(
- "select count(*) from sessions where task_id = ?", (run_task,)).fetchone()[0]
- conn.close()
- check(report_kept and len(report_kept) > 0,
- "the completion report stays on the re-opened goal")
- check(seeded >= 1, "the resurrected run carries a session row (the resume anchor)")
- goal_comments = goal_state(goal)["comments"]
- check(any("edge cases" in c["body"] for c in goal_comments),
- "the resurrecting comment rides the goal thread")
- # force_wake made the parked run offerable at once: the dispatcher
- # hands it back and the resuming assignment carries the notice.
- assignments_before = len(fake.goal_assignments)
- check(wait_for(lambda: len(fake.goal_assignments) > assignments_before or False,
- timeout=60, what="resurrected agent resumes") is not None,
- "the resurrected goal agent resumes on its saddle")
- resumed = fake.goal_assignments[-1]
- check((resumed.get("task") or {}).get("id") == run_task,
- "the resuming assignment is the run task")
- check("re-opened by a human comment" in (resumed.get("resume_notice") or ""),
- "the resume notice names the comment-driven re-open")
- check(any("edge cases" in c["body"]
- for c in (resumed.get("task") or {}).get("comments", []))
- or any("edge cases" in (c.get("text") or "") for c in fake.comment_log),
- "the resuming agent receives the comment (assignment or live push)")
- print("== terminal goal worker: comments stay closed ==")
- conn = db()
- worker = conn.execute(
- "insert into tasks (project_id, goal_id, kind, title, status, priority,"
- " mode, creator, completed_at, created_at)"
- " values (1, ?, 'task', 'Dead worker', 'done', 5,"
- " 'implement', 'goal', strftime('%s','now'), strftime('%s','now'))",
- (goal,)).lastrowid
- conn.commit()
- conn.close()
- worker_page = http_get_page(auth, "/tasks/%d" % worker)
- check("Comments are closed" in worker_page,
- "a terminal goal-owned task page explains the closed comments")
- # The gate lives in the template (statum hides the branch at render;
- # the served markup carries no branch text to match — pages.py's
- # Edit-button precedent): the composer must sit inside the
- # goal-owned-terminal negation and the closed notice inside the
- # positive gate.
- template = open(os.path.join(REPO, "src", "pages", "task_detail.html")).read()
- composer_at = template.find('<form stm-if="!(task.terminal && task.goal_id > 0)"')
- notice_at = template.find('<p stm-if="task.terminal && task.goal_id > 0"')
- check(composer_at > 0 and notice_at > composer_at,
- "the task template gates the composer on goal-owned terminal tasks")
- # The service path is the goal's alone: the page-level gate is the
- # only barrier a human meets, and a direct AddCommentAction post on
- # the dead worker must NOT resurrect it (the action ignores
- # goal-owned terminal tasks).
- state = task_state(auth, worker)
- if state.get("comment"):
- act(auth, state["comment"], {"body": "Sneaky resurrection attempt"})
- check(task_state(auth, worker)["status"] == "done",
- "a comment on a terminal goal worker does not resurrect it")
- else:
- check(True, "a terminal goal worker exposes no comment action at all")
|