|
|
@@ -534,10 +534,14 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
/**
|
|
|
* Answers a goal block (the goal page's single verdict path):
|
|
|
- * the answer lands on the goal row AND on the goal-run task's
|
|
|
- * mirrored task block — the parked-resume machinery then wakes
|
|
|
- * the agent with the verdict as its resume_notice. Plan and
|
|
|
- * completion blocks apply their goal-state transitions:
|
|
|
+ * the answer lands on the goal row AND on EVERY unanswered
|
|
|
+ * mirror of it on the goal-run task — both halves of the
|
|
|
+ * dual-rowed pair settle before any observer pulse fires
|
|
|
+ * (plan 14 B3's mirror-sync: a one-sided pair is exactly the
|
|
|
+ * staleness the dashboard pile suffered); the parked-resume
|
|
|
+ * machinery then wakes the agent with the verdict as its
|
|
|
+ * resume_notice. Plan and completion blocks apply their
|
|
|
+ * goal-state transitions:
|
|
|
*
|
|
|
* - plan + {@link NOTICE_PLAN_APPROVED} → the submission
|
|
|
* becomes goal.plan, status 'active';
|
|
|
@@ -569,6 +573,15 @@ namespace ClankerSaddle.Services {
|
|
|
((!)block).answered_by = answered_by;
|
|
|
yield db.update_async<GoalBlock>((!)block);
|
|
|
|
|
|
+ // Plan 14 B3 mirror-sync ordering: the verdict's events
|
|
|
+ // record FIRST, then both halves of the dual-rowed pair
|
|
|
+ // settle (goal row above, every unanswered mirror below)
|
|
|
+ // before the first observer pulse fires — a one-sided
|
|
|
+ // pair is exactly the staleness the dashboard pile
|
|
|
+ // suffered, and an event-less resume is a lost
|
|
|
+ // context_update. The dispatcher's periodic tick can
|
|
|
+ // strike anywhere in between; by the time either row
|
|
|
+ // reads answered, the events are already committed.
|
|
|
if (((!)block).block_type == GOAL_BLOCK_PLAN) {
|
|
|
if (answer == NOTICE_PLAN_APPROVED) {
|
|
|
if (((!)block).body != null && ((!)block).body.length > 0) {
|
|
|
@@ -596,15 +609,12 @@ namespace ClankerSaddle.Services {
|
|
|
}
|
|
|
yield db.update_async<Goal>((!)goal);
|
|
|
|
|
|
- // The mirrored task block carries the same verdict to the
|
|
|
- // parked goal-run workspace (resume_notice material).
|
|
|
var run = yield goal_run_task(((!)goal).id);
|
|
|
if (run != null) {
|
|
|
foreach (var task_block in yield tasks.list_blocks(((!)run).id)) {
|
|
|
if (task_block.question == ((!)block).question
|
|
|
&& task_block.answer == null) {
|
|
|
yield tasks.answer_block(task_block.id, answer, answered_by);
|
|
|
- break;
|
|
|
}
|
|
|
}
|
|
|
if (((!)block).block_type == GOAL_BLOCK_COMPLETION
|