Skip to content

F1e: planning API for lane G and feedback from review actions - #60

Draft
mchwang wants to merge 1 commit into
feat/f1d-startup-recoveryfrom
feat/f1e-planning-feedback
Draft

mchwang wants to merge 1 commit into
feat/f1d-startup-recoveryfrom
feat/f1e-planning-feedback

Conversation

@mchwang

@mchwang mchwang commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Lane F, step F1, slice F1e: the planning API for lane G, and feedback from review actions. Stacked on #59 (F1d) → #57 → #56 → #53. This is the last F1 slice. Related: #22, #51.

What this does

Planning endpoints for G4 (web/server.ts, per the contract's "Planning API for lane G"):

Endpoint Does
POST /api/plan/import Store.importRevision with the expected revision
POST /api/plan/suggestions E3 SuggestionCoordinator.start, bound to the expected revision and snapshot, with the user's feedback text (4,000 characters or fewer)
GET /api/plan/suggestions/:id reads only the request row
POST /api/plan/suggestions/:id/cancel pending: handle.cancel on the retained SuggestionHandle. Otherwise, or with no handle in this process: Store.cancelSuggestions
POST /api/plan/suggestions/:id/apply Store.applySuggestion with the trusted plan context
  • Every POST goes through Store.userAction, so it replays exactly by actionId.
  • E3's settlement writes (completeSuggestions, and settleSuggestion in close()) run with the shutdown capability. The coordinator closes at shutdown step 6.
  • Starting a suggestion is refused with "Planning agent not available yet." until a PlanningDeps provider is injected (live planning goes through D, D follow-ups required by the F1 runner lifecycle contract #51).
  • ReviewService.planContext() builds the trusted plan context: base entries from git ls-tree at the snapshot's base, and the configured path identity.

Feedback from review actions:

  • A change note, a segment accept and a segment assign now require an actionId (400 without one). The action and its feedback event (change-request, segment-accept, segment-assign) are written in one transaction, inside Store.userAction.
  • A later choice for the same segment links (supersedes) to the latest earlier event for it.
  • Choice keys embed segment content and have no size bound, so an event's sourceRef is choice:<sha256 of the stored choice key>: fixed-size and recomputable.
  • Other actions (questions, approvals, settings) replay exactly when they carry an actionId, and stay backward-compatible without one. A replayed question does not start its agent again.
  • The UI (web/public/app.js) sends crypto.randomUUID() with every review action.

Validation (head bfe30df, rebased onto F1d 5d163f2)

  • npm run typecheck: passes.

  • CI's unit set: 529 passed, 0 failed (includes F1d's new lock test). 10 of those are new, in test/runner-planning-feedback.test.ts, over real HTTP on the demo fixture:

    • a change note and its event, with replay;
    • 400 without an actionId;
    • a segment choice with its fixed-size source, and supersede;
    • no event for a question, and no second agent start on replay;
    • a refusal replayed as the same refusal;
    • planning unavailable;
    • import once per ID, and a stale import refused;
    • start, read and apply exactly once;
    • cancelling a pending suggestion (the provider's signal is aborted) and a ready one;
    • a pending suggestion settled at shutdown.
  • npm run test:browser: 53 passed.

  • Mutation check: six of seven broken versions were caught:

    • a change note recording no event;
    • a feedback action allowed without an ID;
    • a pending cancel skipping the handle;
    • suggestions not closed at shutdown;
    • supersedeLatest ignored;
    • apply bypassing the action table.

    Not caught: removing the !replayed question guard. Questions.start() already refuses a note that is being answered or answered, so the guard is a second layer with no observable effect.

CI failure on the first push

The first CI run failed F1d's cross-process lock test. The cause is fixed on #59 (5d163f2, a lock connection garbage-collected when the caller dropped it), and this branch is rebased onto it.

Test changes to existing tests

  • test/browser/review.spec.ts ("can assign a large foreign change…") and three runner-shutdown tests now send the actionId that the API requires for feedback-producing actions. What they assert is unchanged.
  • runner-shutdown.test.ts and the new planning/feedback test use a 20 s test timeout. Each review load reads git history, so these integration tests take 3–6 s under a full parallel run, over vitest's 5 s default. CI passed on F1c: shutdown wiring and /api/runner #57 with the default, but the margin is small.

Deferred

  • Reject with feedback, accepted findings and needs-human guidance have no review actions yet (F2). Their event kinds and the Store method are ready.
  • The review actions cannot reassign an already-accepted segment, so supersedes is reachable only when that action exists. It is tested at the Store level.
  • Merge initiation through user_actions (contract round 16) needs the merge coordinator to update the saved response when the outcome is recorded. Deferred to F6, the merge handoff.
  • A live planning provider and the issue retrieval for describe() wait for D follow-ups required by the F1 runner lifecycle contract #51 and G4.

🤖 Generated with Claude Code

Planning endpoints over E3's coordinator and the Store: import, suggestion
start/read/cancel/apply, each through Store.userAction; E3's settlement
writes use the shutdown capability and the coordinator closes at shutdown.
Starting a suggestion is refused until a planning provider is injected.
ReviewService.planContext builds the trusted plan context from the base tree.

Review actions: change notes, segment accept and assign require an actionId
and record their feedback event in the same transaction; a later choice links
to the earlier event; choice sources are fixed-size fingerprints. The UI sends
an actionId per action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mchwang added a commit that referenced this pull request Sep 26, 2026
A caller that dropped the returned RunnerLock let its SQLite connection be
garbage-collected, which released the OS lock while the runner was still
alive. Found by a CI failure of the cross-process lock test on #60. The new
test drops the lock and forces GC in a child, and fails without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mchwang
mchwang force-pushed the feat/f1e-planning-feedback branch from b36e017 to bfe30df Compare September 26, 2026 11:02
mchwang added a commit that referenced this pull request Sep 26, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mchwang added a commit that referenced this pull request Sep 26, 2026
* docs: reconcile the design plan with the code

Record where the code differs from the approved plan and update stale status:

- Record Ask as an interim exception to R1: it runs the vendor CLI on the
  host with tools off until lane F moves it into the lane D container.
- Amend D20: there is no "Merge anyway"; to override a blocker, merge on
  GitHub. Matches docs/implementation/guarded-merge.md.
- Tick T1, T2, T4, T5, T10, T13, T14 with test evidence; point Files lines
  at core/linking.ts and core/approvals.ts instead of never-created modules.
- Mark increment 1 merged; add a lane status table (C, D, K done; E, F, H
  progress); record decided open questions (issue ranking, AgentDiff).
- Add a verified status note for design tasks DT2-DT15; none newly ticked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: note merge-queue support in the guarded merge doc

The guarded merge gate doc still said merge-queue branches stay blocked.
#46 (closing #24) added queue lifecycle support. Point to merge-queue.md,
and state that adapters without queue inspection still fail closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: bring plan status up to date with F1 and H4a

Merge main. Record the F1 lifecycle contract (#49) and open F1a-F1c
(#53, #56, #57); record the ranked Issues screen (H4a, #55) with H4b's
trust action remaining; Issues is now a menu link, not a placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: add F1d and Ask PRs to lane status

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Align merge-queue wording with the merged K2/K3 support

README no longer says merge queues block merging; it describes the
enqueue-then-confirm behaviour. The plan's wave-3 note records the old
block as history instead of a live instruction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Record the K-lane queue block as history in the task table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* README: disclose that Ask runs the agent CLI on the host

The plan (R1 exception) says README states this limit; it did not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add F1e (#60) and the #51 merge condition to the F lane row

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* README: distinguish queue-removal retry from changed-head review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Plan: mark the install preflight and npx entry as planned

The CLI checks only the Node version today; say so instead of describing
the git/gh/container/sign-in preflight as current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant