agent-orchestrator/backend/internal
Pritom Mazumdar 3986d488c8
feat(session): support multiple PRs per session (#230)
* feat(session): support multiple PRs per session

A session can now own several pull requests (a root plus stacked
children) instead of being capped at one. The SQLite schema was already
1-session->many-PR (pr.url PK, session_id a plain FK), so this is a
behavioural change across the observe -> persist -> derive -> react
pipeline, not a migration.

- observe: the SCM observer discovers every open PR whose source branch
  matches a session branch or descends from it ("branch/..." stacking),
  attributing each to the owning session; the longest matching branch
  wins so a child session claims its own stacked PRs.
- derive: session status is a worst-wins aggregate over all owned PRs,
  with a stack model (B is a child of A iff B.target == A.source and A is
  open) exposed via prs[] on every session read DTO.
- react: per-PR reactions; a stacked child blocked by an open parent is
  exempt from the rebase/merge-conflict nudge (only the bottom of the
  stack is eligible), and the session completes only when no PR is open
  and at least one merged.
- tests: unit coverage across stack/status/observer/lifecycle, a
  real-SQLite ListPRFactsForSession test for the stacked-PR read path,
  and a functional end-to-end integration test driving the real store +
  lifecycle + observer through attribution, completion, and stacked-child
  nudge suppression.

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

* fix(scm): ignore fork heads in PR attribution and persist discovered siblings before completion

Branch-prefix attribution now requires a discovered PR's head branch to live
in the project repo. A fork PR can reuse a session's branch name while its
commits live in the fork, so the previous code could auto-claim foreign work.
Carry head repo full_name from the REST list response and skip any PR whose
head repo is not the base repo.

discoverNewPRs also writes each newly discovered PR as an open baseline row
before the refresh/lifecycle pass runs. A session can own several PRs, and a
terminal observation triggers a completion check that reads all of the
session's PRs from the store. Without the early write, an open sibling found
in the same poll was not yet durable and the session could terminate while
that PR was still open.

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

* fix(session): surface actionable signals from blocked stacked children; clarify worker prompt

Status aggregation previously dropped any open PR blocked by an open parent,
hiding actionable child signals (failing CI, draft, requested changes,
unresolved comments) behind the parent's status. A blocked child still cannot
merge, so its readiness signals (mergeable/approved/review-pending/open) stay
suppressed, but its problem signals now contribute to the worst-wins aggregate.
The all-blocked fallback is preserved so a session never goes dark.

The worker multi-PR prompt said independent PRs could branch off the base
branch as usual, which conflicts with branch-prefix attribution. Clarify that
a PR may target the base branch, but its source branch must stay under the
session branch namespace for AO to track it.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-17 17:31:28 +05:30
..
adapters feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
cdc feat: ao session claim-pr + spawn --claim-pr wiring (#101) 2026-06-06 00:01:03 +05:30
cli feat(review): configurable AO code review backend (V1) (#192) (#197) 2026-06-15 01:17:17 +05:30
config Use ~/.ao as canonical state home (#233) 2026-06-14 22:52:25 +05:30
daemon feat(review): configurable AO code review backend (V1) (#192) (#197) 2026-06-15 01:17:17 +05:30
daemonmeta fix(cli): verify daemon ownership before stop signal 2026-06-01 01:45:04 +05:30
domain feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
httpd feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
integration feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
lifecycle feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
notify feat: add notifications v1 (#181) 2026-06-14 20:02:32 +05:30
observe feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
ports feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
processalive refactor: simplify session lifecycle and zellij runtime (#62) 2026-06-01 08:42:49 +05:30
review fix(review): reviewer posts to GitHub and records its verdict autonomously (#259) 2026-06-17 16:34:15 +05:30
runfile refactor: simplify session lifecycle and zellij runtime (#62) 2026-06-01 08:42:49 +05:30
service feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
session_manager feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
storage/sqlite feat(session): support multiple PRs per session (#230) 2026-06-17 17:31:28 +05:30
terminal refactor(terminal): per-client zellij attach replaces shared PTY + replay ring (#194) 2026-06-12 15:19:38 +05:30