|
|
@@ -1293,16 +1293,16 @@ def bundle_pages(ctx):
|
|
|
|
|
|
# Accept stores the stable approval wording as the answer (it
|
|
|
# becomes the resume notice the daemon reads; task-level plans are
|
|
|
- # gone — the goal owns the approved markdown).
|
|
|
- act(auth, blocks["plan"]["answer_action"],
|
|
|
- {"answer": "Plan approved. Proceed with implementation."})
|
|
|
+ # gone — the goal owns the approved markdown). Plan 16 S2/R4: the
|
|
|
+ # form posts the verdict MARKER — the server owns the constant.
|
|
|
+ act(auth, blocks["plan"]["answer_action"], {"verdict": "accept"})
|
|
|
detail = task_state(auth, plan_task)
|
|
|
plan_block = [b for b in detail["blocks"] if b["block_type"] == "plan"][0]
|
|
|
check(plan_block.get("show_body") is True,
|
|
|
"answered plan review shows the body again (review section gone)")
|
|
|
check(plan_block.get("answered") is True
|
|
|
and plan_block.get("answer") == "Plan approved. Proceed with implementation.",
|
|
|
- "accept stores the stable approval wording (the resume notice)")
|
|
|
+ "verdict=accept stores the stable approval wording server-side (the resume notice)")
|
|
|
|
|
|
print("== B1: highlight-to-comment quote dialog ==")
|
|
|
status, page = http("GET", "/tasks/%d" % plan_task, timeout=15)
|
|
|
@@ -1329,12 +1329,21 @@ def bundle_pages(ctx):
|
|
|
"pending review block hides its duplicate body preview")
|
|
|
check(review_block.get("body", "").startswith("# The change"),
|
|
|
"review body itself still arrives in state (B2 counterpart)")
|
|
|
- act(auth, review_block["answer_action"],
|
|
|
- {"answer": "Review approved. Continue with the task."})
|
|
|
+ act(auth, review_block["answer_action"], {"verdict": "accept"})
|
|
|
detail = task_state(auth, plan_task)
|
|
|
review_block = [b for b in detail["blocks"] if b["block_type"] == "review"][0]
|
|
|
check(review_block.get("show_body") is True,
|
|
|
"answered review shows the body again (banner gone)")
|
|
|
+ check(review_block.get("answer") == "Review approved. Continue with the task.",
|
|
|
+ "the review accept form's verdict marker resolves to the stable wording")
|
|
|
+ # Plan 16 S2/R4: no verdict constant ships in any template — the
|
|
|
+ # accept forms carry only the verdict marker.
|
|
|
+ task_page_html = http_get_page(auth, "/tasks/%d" % plan_task)
|
|
|
+ check("Plan approved. Proceed with implementation." not in task_page_html
|
|
|
+ and "Review approved. Continue with the task." not in task_page_html,
|
|
|
+ "the task page ships no verdict constants (server-owned wording)")
|
|
|
+ check('name="verdict" value="accept"' in task_page_html,
|
|
|
+ "the accept forms post the verdict marker")
|
|
|
|
|
|
print("== B2: question block body above options ==")
|
|
|
# Contract side (A2 will restore bodies end-to-end): a question
|
|
|
@@ -4614,8 +4623,9 @@ def bundle_answers(ctx):
|
|
|
plan_block = park_on_plan(accept_task, "# Steps\n\n1. Wire\n2. Test")
|
|
|
check(plan_block.get("answered") is not True,
|
|
|
"the plan block waits for a human verdict")
|
|
|
- act(auth, plan_block["answer_action"],
|
|
|
- {"answer": "Plan approved. Proceed with implementation."})
|
|
|
+ # Plan 16 S2: the accept form posts the verdict marker; the server
|
|
|
+ # builds the stable constant (byte-identical wire).
|
|
|
+ act(auth, plan_block["answer_action"], {"verdict": "accept"})
|
|
|
check(wait_for(lambda: any(
|
|
|
int(p.get("task", {}).get("id") or 0) == accept_task
|
|
|
and p.get("session_id") != accept_parked_session
|
|
|
@@ -4719,8 +4729,7 @@ def bundle_answers(ctx):
|
|
|
detail = task_state(auth, review_task)
|
|
|
verdict_block = [b for b in detail["blocks"]
|
|
|
if b["block_type"] == "review"][0]
|
|
|
- act(auth, verdict_block["answer_action"],
|
|
|
- {"answer": "Review approved. Continue with the task."})
|
|
|
+ act(auth, verdict_block["answer_action"], {"verdict": "accept"})
|
|
|
reviewer.kill()
|
|
|
act(auth, saddle_card(auth, "resume-reviewer")["refresh"], {})
|
|
|
check(wait_for(lambda: saddle_card(auth, "resume-reviewer")["status"] == "offline"
|
|
|
@@ -5431,10 +5440,11 @@ def bundle_goals(ctx):
|
|
|
and (state["plan"] or "") == "",
|
|
|
"goals.plan stays empty while the revision is only pending (accept-gated, S1)")
|
|
|
# Approve: goal.plan = v2, status active, agent resumes and parks.
|
|
|
+ # Plan 16 S2: the accept posts the verdict MARKER — the server
|
|
|
+ # resolves the goal-plan kind and owns the constant.
|
|
|
fake.goal_script = [("suspend",)]
|
|
|
pending = state["plan_pending_block"]
|
|
|
- act(auth, pending["answer_action"],
|
|
|
- {"answer": "Plan approved. Proceed with implementation."})
|
|
|
+ act(auth, pending["answer_action"], {"verdict": "accept"})
|
|
|
check(wait_for(lambda: goal_state(goal1)["status"] == "active" or False,
|
|
|
timeout=60, what="approved plan activates the goal") is not None,
|
|
|
"approving the plan activates the goal")
|
|
|
@@ -5735,14 +5745,26 @@ def bundle_goals(ctx):
|
|
|
"the goal-run task parks on the completion review")
|
|
|
check(state["compare_url"].endswith("/compare/main...goal/flange"),
|
|
|
"the completion review links the compare view")
|
|
|
- # Reject first: feedback returns the goal to active.
|
|
|
+ # Reject first: feedback returns the goal to active. Plan 16 S2:
|
|
|
+ # the goal page's reject posts raw `feedback` — the SERVER wraps
|
|
|
+ # it with the completion-review prefix (byte-identical to the
|
|
|
+ # historical client-built answer).
|
|
|
fake.goal_script = [("suspend",)]
|
|
|
act(auth, state["completion_pending_block"]["answer_action"],
|
|
|
- {"answer": "Not done — the docs are missing"})
|
|
|
+ {"feedback": "Not done — the docs are missing"})
|
|
|
check(wait_for(lambda: goal_state(goal1)["status"] == "active" or False,
|
|
|
timeout=30, what="rejected completion reactivates") is not None,
|
|
|
"rejecting the completion returns the goal to active")
|
|
|
conn = db()
|
|
|
+ rejected_answer = conn.execute(
|
|
|
+ "select answer from task_blocks where task_id = ?"
|
|
|
+ " and type = 'completion' order by id desc", (run_task,)).fetchone()[0]
|
|
|
+ conn.close()
|
|
|
+ check(rejected_answer
|
|
|
+ == "Review feedback received:\n\nNot done — the docs are missing",
|
|
|
+ "the completion rejection wraps feedback with the stable prefix (%r)"
|
|
|
+ % rejected_answer)
|
|
|
+ conn = db()
|
|
|
rejected_report = conn.execute(
|
|
|
"select completion_report from goals where id = ?", (goal1,)).fetchone()[0]
|
|
|
conn.close()
|
|
|
@@ -5825,8 +5847,11 @@ def bundle_goals(ctx):
|
|
|
check(no_push_column,
|
|
|
"no stored push snapshot exists (F9: the goal row never records it)")
|
|
|
state = goal_state(goal1)
|
|
|
+ # The passing accept posts the verdict MARKER (the goal page's
|
|
|
+ # accept form shape, plan 16 S2) — the server resolves the
|
|
|
+ # completion kind and stores the stable approval wording.
|
|
|
act(auth, state["completion_pending_block"]["answer_action"],
|
|
|
- {"answer": "Review approved. Continue with the task."})
|
|
|
+ {"verdict": "accept"})
|
|
|
check(wait_for(lambda: goal_state(goal1)["status"] == "complete" or False,
|
|
|
timeout=30, what="accepted completion completes") is not None,
|
|
|
"accepting the completion completes the goal once origin is current")
|
|
|
@@ -7039,7 +7064,7 @@ def bundle_goalui(ctx):
|
|
|
"the done entry + state pair raises nothing more (one block, ever)")
|
|
|
state = goal_state(goal)
|
|
|
act(auth, state["completion_pending_block"]["answer_action"],
|
|
|
- {"answer": "Review approved. Continue with the task."})
|
|
|
+ {"verdict": "accept"})
|
|
|
check(wait_for(lambda: goal_state(goal)["status"] == "complete" or False,
|
|
|
timeout=30, what="goalui goal completes") is not None,
|
|
|
"accepting the completion completes the goal")
|
|
|
@@ -7053,6 +7078,77 @@ def bundle_goalui(ctx):
|
|
|
check(stragglers == 0,
|
|
|
"no unanswered straggler rows survive the completion")
|
|
|
|
|
|
+ print("== S2: server-owned verdicts + the container-resolved reject ==")
|
|
|
+ # A fresh goal drives the verdict paths the goal page's forms now
|
|
|
+ # use: verdict markers for accept, raw `feedback` for reject, and
|
|
|
+ # the block resolution living in the review CONTAINER (not
|
|
|
+ # goal.plan_pending_block — the diagnosed completion-review bug).
|
|
|
+ fake.goal_script = [("plan", "# S2 plan\n\nOne step")]
|
|
|
+ act(auth, slot_public(auth, "/goals", "goals")["create"], {
|
|
|
+ "project_id": "1", "title": "S2 verdict goal",
|
|
|
+ "brief": "Covers the plan-16 S2 verdict paths.",
|
|
|
+ "branch_name": "goal/s2-verdicts"})
|
|
|
+ conn = db()
|
|
|
+ s2_goal = int(conn.execute(
|
|
|
+ "select id from goals where title = 'S2 verdict goal'").fetchone()[0])
|
|
|
+ conn.close()
|
|
|
+ act(auth, goal_state(s2_goal)["start"], {})
|
|
|
+ check(wait_for(lambda: goal_state(s2_goal)["status"] == "plan_review" or False,
|
|
|
+ timeout=90, what="S2 goal enters plan review") is not None,
|
|
|
+ "the S2 goal enters plan review")
|
|
|
+ s2_state = goal_state(s2_goal)
|
|
|
+ s2_pending = s2_state["plan_pending_block"]
|
|
|
+
|
|
|
+ # (1) A remark-less, text-less rejection is refused: the action
|
|
|
+ # errors and the block keeps waiting.
|
|
|
+ refusal = act(auth, s2_pending["answer_action"], {"feedback": " "})
|
|
|
+ check(any(d.get("type") == "notify" and d.get("kind") == "error"
|
|
|
+ and "answer is required" in (d.get("message") or "").lower()
|
|
|
+ for d in refusal),
|
|
|
+ "a remark-less, text-less rejection is refused with an error")
|
|
|
+ conn = db()
|
|
|
+ s2_still_open = conn.execute(
|
|
|
+ "select answer from task_blocks where id = ?",
|
|
|
+ (s2_pending["id"],)).fetchone()[0]
|
|
|
+ conn.close()
|
|
|
+ check(s2_still_open is None,
|
|
|
+ "the refused rejection leaves the block unanswered")
|
|
|
+
|
|
|
+ # (3) The goal page template ships no verdict constants and its
|
|
|
+ # script resolves the review block from ANY [data-plan-review]
|
|
|
+ # container via the open-blocks list (the completion-review fix).
|
|
|
+ # Fetched while the review is open so the accept form renders.
|
|
|
+ s2_page = http_get_page(auth, "/goals/%d" % s2_goal)
|
|
|
+ check("Plan approved. Proceed with implementation." not in s2_page
|
|
|
+ and "Review approved. Continue with the task." not in s2_page,
|
|
|
+ "the goal page ships no verdict constants (server-owned wording)")
|
|
|
+ check('name="verdict" value="accept"' in s2_page,
|
|
|
+ "the goal page's accept forms post the verdict marker")
|
|
|
+ check("resolveReviewBlock" in s2_page and "goal.open_blocks" in s2_page,
|
|
|
+ "the reject flow resolves its block from the open-blocks list (container-keyed)")
|
|
|
+ check("statum.act(block.answer_action, { feedback: feedback })" in s2_page,
|
|
|
+ "the reject flow posts raw feedback (the server wraps the prefix)")
|
|
|
+ check("extraText.length === 0" in s2_page,
|
|
|
+ "a remark-less rejection with textarea content is allowed (S2)")
|
|
|
+
|
|
|
+ # (2) The goal page's reject rides `feedback` (the client composes
|
|
|
+ # the numbered-remarks body) and the SERVER wraps it with the plan
|
|
|
+ # prefix — byte-identical to the historical client-built answer.
|
|
|
+ act(auth, s2_pending["answer_action"],
|
|
|
+ {"feedback": "> ## One step\n\n1. Tighten it\n\n2. Name the owner"})
|
|
|
+ conn = db()
|
|
|
+ s2_wrapped = conn.execute(
|
|
|
+ "select answer from task_blocks where id = ?",
|
|
|
+ (s2_pending["id"],)).fetchone()[0]
|
|
|
+ conn.close()
|
|
|
+ check(s2_wrapped
|
|
|
+ == "Plan feedback received:\n\n"
|
|
|
+ "> ## One step\n\n1. Tighten it\n\n2. Name the owner",
|
|
|
+ "the plan rejection wraps the client-shaped body with the stable prefix (%r)"
|
|
|
+ % s2_wrapped)
|
|
|
+ check(goal_state(s2_goal)["status"] == "planning",
|
|
|
+ "the feedback rejection returns the agent to planning")
|
|
|
+
|
|
|
|
|
|
BUNDLES_ORDER = ("pages", "dispatch", "subtasks", "lineage",
|
|
|
"allocation", "lifecycle", "answers", "push", "goals",
|