docs(6205): milestones comments state the reason, not the instance that taught it

The pool-exhaustion, handshake-size and stepless-roadmap comments state the
condition the code guards instead of the measured incident; citations go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:26:50 -04:00
co-authored by Claude Opus 5.5
parent 29fd64f67e
commit 757d016a0c
+22 -23
View File
@@ -19,14 +19,14 @@ OPEN_STEP_STATUSES = ("todo", "in_progress")
def embed_milestone(milestone: Milestone) -> None: def embed_milestone(milestone: Milestone) -> None:
"""Refresh a milestone's vectors, fire-and-forget (milestone 415). """Refresh a milestone's vectors, fire-and-forget.
At the service, so every path that writes a milestone gets it — the lesson At the service, so every path that writes a milestone gets it: a record
embed_note records (#2056): a record written through a door that forgot the written through a door that forgot the call stays out of search until a
call stays out of search until a restart. Exceptions are swallowed because restart. Exceptions are swallowed because
a milestone that saved must not fail on its index refresh; no running loop a milestone that saved must not fail on its index refresh; no running loop
(a script, a unit test) is ordinary. A delete racing the refresh wins: the (a script, a unit test) is ordinary. A delete racing the refresh wins: the
upsert claims the milestone's row first (#3262). upsert claims the milestone's row first.
""" """
try: try:
import asyncio import asyncio
@@ -250,12 +250,12 @@ async def get_project_milestone_summaries(
The per-project version below is a nested fan-out: one query to list a The per-project version below is a nested fan-out: one query to list a
project's milestones, then one more per milestone for its progress. Called project's milestones, then one more per milestone for its progress. Called
for 25 projects concurrently it asked for ~250 pooled connections against a for many projects concurrently it asks for far more pooled connections than
pool of 15, and every one of them waited out the 30-second checkout timeout the pool holds, and every one of them waits out the checkout timeout. This
(#2384). This does the same work in a fixed number of queries and one does the same work in a fixed number of queries and one
session: the milestones, their step counts, and their open steps. session: the milestones, their step counts, and their open steps.
Each row carries `next_step` — the earliest open step, or None (#4154). Each row carries `next_step` — the earliest open step, or None.
That is NOT the same question `services/placement.py` answers: placement That is NOT the same question `services/placement.py` answers: placement
knows which step you are on and names the next one AFTER it, while a knows which step you are on and names the next one AFTER it, while a
listing has no current step, so the earliest open one is the whole answer. listing has no current step, so the earliest open one is the whole answer.
@@ -279,7 +279,7 @@ async def get_project_milestone_summaries(
next_step: dict[int, dict] = {} next_step: dict[int, dict] = {}
if milestones: if milestones:
milestone_ids = [m.id for m in milestones] milestone_ids = [m.id for m in milestones]
# Both step queries below take the SAME visibility clause (rule 78). # Both step queries below take the SAME visibility clause.
# They have to: `next_step` names a step and the counts beside it # They have to: `next_step` names a step and the counts beside it
# say how many there are, so a row that could name a step its own # say how many there are, so a row that could name a step its own
# progress excludes would be reporting two different milestones. # progress excludes would be reporting two different milestones.
@@ -304,8 +304,8 @@ async def get_project_milestone_summaries(
step_touched[milestone_id] = latest step_touched[milestone_id] = latest
# ONE query for every milestone in the batch, not one per row. # ONE query for every milestone in the batch, not one per row.
# #2384 was exactly this listing fanned out per milestone, and it # Fanned out per milestone, this listing drains the connection
# drained the connection pool; a third flat query keeps the cost # pool; a third flat query keeps the cost
# constant in the number of plans. Ordered the way # constant in the number of plans. Ordered the way
# services/placement.py orders steps — creation order, the order a # services/placement.py orders steps — creation order, the order a
# plan is written and a batch create inserts — so the first row per # plan is written and a batch create inserts — so the first row per
@@ -331,14 +331,14 @@ async def get_project_milestone_summaries(
entry.update(_progress_from_counts(counts.get(m.id, {}))) entry.update(_progress_from_counts(counts.get(m.id, {})))
# A milestone's own updated_at doesn't move when its steps do, so a # A milestone's own updated_at doesn't move when its steps do, so a
# plan whose steps closed today would read as untouched since it was # plan whose steps closed today would read as untouched since it was
# written (#4045). Touched is the later of the two. # written. Touched is the later of the two.
touched = [t for t in (m.updated_at, step_touched.get(m.id)) if t] touched = [t for t in (m.updated_at, step_touched.get(m.id)) if t]
entry["last_touched_at"] = max(touched).isoformat() if touched else None entry["last_touched_at"] = max(touched).isoformat() if touched else None
# Always present, None included. "8 of 9 done" tells a reader there is # Always present, None included. "8 of 9 done" tells a reader there is
# an open step and not WHICH, and a gap that shape gets filled from # an open step and not WHICH, and a gap that shape gets filled from
# whatever id is nearest to hand — a retrieval hint carries an id and a # whatever id is nearest to hand — a retrieval hint carries an id and a
# title and no status, and that is how a done step was reported as the # title and no status, so a done step can be reported as the open one.
# open one (#4154). A listing that names it leaves nothing to guess. # A listing that names it leaves nothing to guess.
entry["next_step"] = next_step.get(m.id) entry["next_step"] = next_step.get(m.id)
out.setdefault(m.project_id, []).append(entry) out.setdefault(m.project_id, []).append(entry)
return out return out
@@ -352,11 +352,10 @@ async def get_project_milestone_summary(user_id: int, project_id: int) -> list[d
# What a milestone LISTING needs: enough to say what each plan is, how far # What a milestone LISTING needs: enough to say what each plan is, how far
# along it is, and which step is next. The plan itself (`body`) is # along it is, and which step is next. The plan itself (`body`) is
# get_milestone's job. Summaries once carried it, and on a project with 39 # get_milestone's job: on a project with a few dozen milestones, plan bodies
# milestones enter_project came to ~222k characters, 168k of them plan bodies. That is past what an MCP client will # would push enter_project past what an MCP client accepts as a tool result,
# accept as a tool result, so the session handshake arrived as a file to page # and the session handshake would arrive as a file to page through.
# through (#4045). user_id / project_id / timestamps repeat what the caller # user_id / project_id / timestamps repeat what the caller already knows.
# already knows.
_BRIEF_FIELDS = ( _BRIEF_FIELDS = (
"id", "title", "description", "status", "order_index", "id", "title", "description", "status", "order_index",
"total", "completed", "pct", "status_counts", "next_step", "total", "completed", "pct", "status_counts", "next_step",
@@ -391,9 +390,9 @@ def unplanned_milestones(
A plan written as a milestone with a description and no steps is open work A plan written as a milestone with a description and no steps is open work
that nothing else names. It is never "touched" — touching is a step that nothing else names. It is never "touched" — touching is a step
changing — so the recency list that brief_milestone_summary(limit=) builds changing — so the recency list that brief_milestone_summary(limit=) builds
can never reach it, and progress reads 0% either way. A project whose can never reach it, and progress reads 0% either way. Unlisted, a roadmap
roadmap was written that way ended up with every later plan opened as a written that way gets every later plan opened as a new milestone beside the
new milestone beside the one that already described it (milestone 415). one that already described it.
`exclude_ids` drops milestones a caller already listed. Kept in roadmap `exclude_ids` drops milestones a caller already listed. Kept in roadmap
order (order_index, then creation), the order they were written in. order (order_index, then creation), the order they were written in.