Outcome
Expose stack creation and extension on the GitHub-shaped API: create a stack from ordered PR numbers, append a PR to its top, and read stacks. Every mutation is explicit; automatic chain detection may suggest, never assume.
Context
docs/stacked-prs.md sections 9, 15, 17, and 18 define the surface. Register routes in OpenAgentsWeb.APIRouteAuthority, gate writes behind the forge:write token scope, and reuse the idempotency-key pattern from repository creation.
Acceptance criteria
POST /repos/:owner/:repo/stacks accepts trunk ref, bottom-to-top PR numbers, expected head OIDs, and an idempotency key.
- The validation chain runs inside one metadata transaction with row locks: permissions, open PRs, same repository, no active membership elsewhere, resolved base/head refs, contiguous direct-base chain, snapshot OIDs, boundary assignment, outbox events.
- A concurrent modification mismatching
expected_stack_version returns 409 Conflict; a retried idempotency key returns the original result.
POST .../stacks/:number/append validates the new PR targets the current top head and bumps the version.
- Read endpoints return stack number, entries with positions and boundary OIDs, health, and version.
- Restructure, unstack, and dissolve reject or route through explicit operations rather than silent edits.
Verification
OpenAgentsWeb.ConnCase tests per route covering success, each rejection reason, conflict, and idempotent retry. Run mix precommit.
Dependencies
Stack schema (#47) and git primitives (#46).
Outcome
Expose stack creation and extension on the GitHub-shaped API: create a stack from ordered PR numbers, append a PR to its top, and read stacks. Every mutation is explicit; automatic chain detection may suggest, never assume.
Context
docs/stacked-prs.mdsections 9, 15, 17, and 18 define the surface. Register routes inOpenAgentsWeb.APIRouteAuthority, gate writes behind theforge:writetoken scope, and reuse the idempotency-key pattern from repository creation.Acceptance criteria
POST /repos/:owner/:repo/stacksaccepts trunk ref, bottom-to-top PR numbers, expected head OIDs, and an idempotency key.expected_stack_versionreturns409 Conflict; a retried idempotency key returns the original result.POST .../stacks/:number/appendvalidates the new PR targets the current top head and bumps the version.Verification
OpenAgentsWeb.ConnCasetests per route covering success, each rejection reason, conflict, and idempotent retry. Runmix precommit.Dependencies
Stack schema (#47) and git primitives (#46).