Commit Graph
2 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5 46d9134b10 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>
2026-09-14 08:43:04 -04:00
bvandeusenandClaude Opus 5 441a1ac31d fix(#4016): records that cite each other are created together, and a guessed id is refused
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 1m2s
CI & Build / integration (push) Successful in 1m0s
CI & Build / Python tests (push) Successful in 1m39s
CI & Build / Build & push image (push) Successful in 39s
Sessions predicted the ids their next creates would get and wrote them into
plan bodies and reference notes before the records existed. The database
never collides; the sequence is shared by every session and user, so any
concurrent create took the guessed numbers and the references pointed at
someone else's records.

- create_records (new MCP tool) and start_planning(body=, steps=) create
  their records in ONE transaction: insert, flush for the real ids, rewrite
  {{ref:N}} / {{ref:milestone}} placeholders as #id "title", commit. No
  prediction, no waiting, no stub records left behind when a batch fails.
  Ids need not be consecutive and nothing depends on it.
- Every MCP create/update of a note, task or milestone refuses a #N sitting
  just above the highest assigned id (within 50): that can only be a guess.
  Refusal, not warning. Numbers far above the max (PRs, forge issues) pass.
- notes.build_note splits validation out of create_note so the batch
  validates records exactly as a single create does.
- writing-plans and using-scribe say to pass steps up front and never write
  an unassigned id; plugin version minted.

Integration test runs six concurrent batches and checks each resolves its
placeholders to its own records, and that a failing batch writes nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 08:33:56 -04:00