feat(409): a task write returns where the task sits (#4010)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 57s
CI & Build / Python tests (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 27s

Step 1 of milestone 409 "Response shapes". An agent reporting finished work
is asked to say which milestone it belongs to, which step of how many, and
what is next. Without those facts to hand it reconstructs them, and a
reconstruction reads exactly like the truth when it is wrong.

create_task and update_task (MCP) and the REST create/update task routes now
return a placement block: project; and for a task in a milestone, the
milestone, position {step, of}, progress {completed, total, pct} and next
(the next open step, falling back to the earliest open one before it).

- Step order is creation order, not get_milestone listing order, which
  reshuffles on every update.
- Siblings are read through readable_notes_clause; position and progress
  are computed over that same readable set, so a collaborator is never shown
  a step title they cannot open, and a note share alone reveals no plan.
- Fail-open and omitted when empty, like every in-band decoration.
- _no_embedding moves into conftest as one opt-in fixture for both
  integration modules that need it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-14 08:43:04 -04:00
co-authored by Claude Opus 5
parent 441a1ac31d
commit 46d9134b10
7 changed files with 320 additions and 14 deletions
+3
View File
@@ -6,6 +6,7 @@ from scribe.auth import login_required, get_current_user_id
from scribe.models.note import TaskPriority, TaskStatus
from scribe.routes.utils import not_found, parse_iso_date, parse_pagination
from scribe.services.access import can_write_note
from scribe.services import placement as placement_svc
from scribe.services import systems as systems_svc
from scribe.services.notes import (
create_note,
@@ -151,6 +152,7 @@ async def create_task_route():
await systems_svc.set_record_systems(uid, task.id, data["system_ids"])
out = task.to_dict()
out["systems"] = [s.to_dict() for s in await systems_svc.list_record_systems(uid, task.id)]
await placement_svc.attach_placement(uid, out, task)
return jsonify(out), 201
@@ -267,6 +269,7 @@ async def update_task_route(task_id: int):
await systems_svc.set_record_systems(uid, task_id, data["system_ids"])
out = task.to_dict()
out["systems"] = [s.to_dict() for s in await systems_svc.list_record_systems(uid, task_id)]
await placement_svc.attach_placement(uid, out, task)
return jsonify(out)