Milestone 415: an existing plan is found before a new one is made #159

Merged
bvandeusen merged 8 commits from dev into main 2026-09-15 14:23:32 -04:00
Owner

Milestone 415 "An existing plan is found before a new one is made — milestones without steps count as open work", plus the #4081 planning payload fix.

  • #4081 "start_planning reply was 92k chars": planning reads now list applicable rules by id and title instead of restating them.
  • #4076 "unplanned milestones": enter_project lists active milestones with no steps as unplanned_milestones.
  • #4077 "board collapse": the No Milestone group collapses, and every group's Done column starts folded. Checked by the operator.
  • #4078 "milestone search": milestones are searchable by meaning via search(content_type="milestone"). New milestone_embeddings table (migration 0102) with a startup backfill.
  • #4079 "the plan gate": start_planning and create_milestone return the active milestone that already has this title, or reads as the same plan, instead of creating a second one. force=true bypasses it. The new Settings field "Existing-plan match threshold" defaults to 0.90.
  • #4080 "the instructions": the writing-plans and using-scribe skills, tool descriptions and _INSTRUCTIONS tell sessions to find the existing plan first and file related work into it. Plugin version 2026.09.15.1744.

CI run 6912 on fb36599 passed: lint, typecheck, unit, integration, plugin hooks and image build.

🤖 Generated with Claude Code

https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy

Milestone 415 "An existing plan is found before a new one is made — milestones without steps count as open work", plus the #4081 planning payload fix. - **#4081 "start_planning reply was 92k chars":** planning reads now list applicable rules by id and title instead of restating them. - **#4076 "unplanned milestones":** `enter_project` lists active milestones with no steps as `unplanned_milestones`. - **#4077 "board collapse":** the No Milestone group collapses, and every group's Done column starts folded. Checked by the operator. - **#4078 "milestone search":** milestones are searchable by meaning via `search(content_type="milestone")`. New `milestone_embeddings` table (migration 0102) with a startup backfill. - **#4079 "the plan gate":** `start_planning` and `create_milestone` return the active milestone that already has this title, or reads as the same plan, instead of creating a second one. `force=true` bypasses it. The new Settings field "Existing-plan match threshold" defaults to 0.90. - **#4080 "the instructions":** the writing-plans and using-scribe skills, tool descriptions and `_INSTRUCTIONS` tell sessions to find the existing plan first and file related work into it. Plugin version 2026.09.15.1744. CI run 6912 on fb36599 passed: lint, typecheck, unit, integration, plugin hooks and image build. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
bvandeusen added 8 commits 2026-09-15 14:23:27 -04:00
fix(rules): planning reads list rules by id and title instead of restating them (#4081)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 53s
CI & Build / TypeScript typecheck (push) Successful in 1m3s
CI & Build / Python tests (push) Failing after 1m4s
CI & Build / Build & push image (push) Skipped
ac01eee040
start_planning on project 2 replied with 92,645 characters, 65k of them
applicable_rules. Milestone 414 made a project's listing every global rule
tagged to an area it works in (before, the rules of subscribed rulebooks, and
project 2 subscribed to none), and the non-brief rules_payload sent each as a
full rule_brief. get_milestone, get_project and get_task carried the same.

Every rules_payload form now lists: id, title, the topic a global rule sits in,
and `via` for a co_surfaces partner. get_rule reads one in full, and retrieval
delivers them in full when work matches — the reasoning #4045 applied to the
handshake. A test pins 81 full-length rules under 6k characters.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
feat(mcp): enter_project names active milestones with no steps as open work (#4076)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / Build & push image (push) Canceled after 0s
CI & Build / integration (push) Canceled after 42s
CI & Build / TypeScript typecheck (push) Canceled after 42s
CI & Build / Python tests (push) Canceled after 47s
184a3e026d
A plan written as a milestone with a description and no steps was invisible to
the session handshake: it lists the 5 most recently touched milestones (#4045),
and touching is a step changing, so a step-less milestone can never qualify.
FabledLibrarian's roadmap (nine such milestones) sat unseen while later plans
were opened as new milestones beside the ones that already described them.

enter_project adds `unplanned_milestones`: active milestones with no steps, in
roadmap order, id/title/description, up to 10 with an omitted count, none
repeated from the recent list, and absent when there are none. The docstring
says what they are for: check them before starting a new milestone, and add
steps to a match with create_records(milestone_id=...).

Milestone 415 step 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
test(rules): rules_payload fixtures carry a title, as every rule_brief does (#4081)
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Build & push image (push) Canceled after 0s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Python tests (push) Canceled after 1m27s
e886bd2a87
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
feat(board): the No Milestone group collapses, and every group's Done column starts folded (#4077)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m35s
CI & Build / Build & push image (push) Successful in 35s
6d0dee48fa
Operator, 2026-09-15: the unmilestoned group should collapse, "especially the
done column as it currently consume a lot of vertical space for [work] that's
already done."

- The "No Milestone" group gets the milestones' chevron and collapse, keyed as
  0 in the same Set (no milestone id is 0), and starts collapsed on first load
  when everything in it is finished — the rule finished milestones already
  follow.
- Each group's Done column header becomes a button that folds its cards, with
  the count still showing and aria-expanded set. Folded by default: done work is
  the part of a board nobody is reading.
- Not persisted, matching the milestone collapse beside it.

Milestone 415 step 2.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
feat(search): milestones are searchable by meaning — "is there already a plan for this?" (#4078)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m37s
CI & Build / Build & push image (push) Successful in 28s
3a501c2cac
`search` covered notes, tasks and rules, and a milestone — the record a plan
lives in — could not be found. A project whose roadmap was written as
milestones had every later plan opened beside the one that already described
it, because nothing could have told the session it existed.

- milestone_embeddings (migration 0102): the third sibling of note_ and
  rule_embeddings, for note 3163's reason — the search is milestone-specific.
  The document is title — description, then description and the plan body,
  so a roadmap milestone with no description is still found by its design.
- Written on create, on a title/description/body update, and for a plan made
  through start_planning / create_records, fire-and-forget with the parent-row
  claim (#3262); a startup backfill covers every existing milestone. Derived,
  so it joins _NOT_INCLUDED beside the other embeddings.
- semantic_search_milestones: a project's milestones when the caller can read
  it (access.can_read_project), otherwise the caller's own; optional status.
- search(content_type="milestone"): id, title, description, status, project
  and progress. Its own shape, and not part of "all", whose results are
  note-shaped. The docstring says what it is for: ask before start_planning.
- Integration test on real Postgres: found in its project and not another,
  status narrows, an unreadable project returns nothing.

Milestone 415 step 3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
feat(planning): start_planning hands back the active plan that already covers the work (#4079)
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / integration (push) Successful in 1m10s
CI & Build / TypeScript typecheck (push) Successful in 1m15s
CI & Build / Python tests (push) Failing after 1m22s
CI & Build / Build & push image (push) Skipped
59407728e6
Step 4 of milestone 415 "An existing plan is found before a new one is made".
A session that could not see an existing plan made a second one beside it.
start_planning and create_milestone now ask first: an ACTIVE milestone in the
project with the same title, or one that reads as the same plan (title, design
and steps against milestone embeddings), is returned with its progress and a
pointer to create_records(milestone_id=...). Nothing is created; force=true
bypasses.

- dedup.find_matching_plan / plan_gate / plan_match_response; access-checked
  before either arm (rule 78), fail-open like the other gates.
- Done milestones never block; the semantic arm needs 200+ chars of candidate.
- kb_plan_match_threshold (default 0.90) is a setting, in the Settings view,
  and pinned against the Python default by test_settings_defaults_agree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
test_nothing_else_builds_the_embedding_document_itself caught start_planning
building f"{title}\n{body}" inline for the plan gate's candidate text. That is
the embedded-document shape; plan_candidate_text now takes (title, body) pairs
and calls embedding_text, so the candidate moves with the corpus it is ranked
against (#2486).

Also carries the create_task / create_records milestone_id docstring lines from
step 5 (#4080), which share the file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
docs(plugin): find the existing plan before making one, and file related work into it (#4080)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 57s
CI & Build / TypeScript typecheck (push) Successful in 1m15s
CI & Build / Python tests (push) Successful in 1m46s
CI & Build / Build & push image (push) Successful in 35s
fb36599f2d
Step 5 of milestone 415 "An existing plan is found before a new one is made".
Sessions opened a second milestone beside the roadmap milestone that already
covered the work, and filed related tasks loose, because no surface told them
to look first.

- writing-plans: a section on finding the plan that exists (enter_project's
  unplanned_milestones, search(content_type="milestone"), list_milestones);
  when an active milestone covers the work, add steps to it; a second
  milestone only for a separate arc; the gate's existing_milestone reply.
- using-scribe: "when you plan" gains the same check and milestone_id on
  related tasks.
- _INSTRUCTIONS PLAN line points at the milestone search (1,689 of 2,000).
- test_guidance_ownership pins the topic on writing-plans.
- Plugin version minted: 2026.09.15.1744.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
bvandeusen merged commit c2c92a8421 into main 2026-09-15 14:23:32 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledScribe#159