Repository navigation
[RFC]: Deliver units through individual PRs to the base branch #553
Description
Implementation tracker: 13 linked sub-issues, #555–#567. Start with #555; the ordered dependency table and PR boundaries are in section 9.
Summary
Add an opt-in Unit PRs to base branch strategy, tentatively pr-per-unit-to-base. Each independently deliverable unit starts from the current target branch, opens its own PR to that branch, and must be verified as merged before dependent units start. The target is each repository's configured base branch; main is the common example, not a hardcoded name.
There is no final feature-sized intent-to-base PR in this strategy. Existing intent-pr and pr-per-unit behavior remains available.
Recommendation: pursue this as an additive delivery strategy. It fits features that can be delivered incrementally. The significant work is defining publication boundaries, preserving required reviews, and recovering after partial delivery—not simply changing a PR's target.
This is a proposal for discussion, not an implementation or a change to review/merge permissions.
Motivation
Large features currently retain an aggregate integration boundary even when their units are reviewed separately. We want smaller PRs that actually reach the target branch, with a clear sequence that can be tackled one unit at a time.
Expected benefits:
- Review and integrate a bounded change while its context is fresh.
- Let a dependent unit build on code already accepted into
main. - Reduce the final integration backlog and the need to re-review an entire feature.
- Make delivered progress visible before the whole intent finishes.
The tradeoff is incremental exposure: every merged unit must leave the repository in an acceptable state, including repositories that deploy on every merge. Good unit planning remains necessary; a strategy setting cannot make an oversized unit small.
Detailed design
1. Current behavior and the proposed difference
Investigation baseline: main at 860cdc60fe05a2c04ea98d008660bd0ce770854a, inspected on 2026-10-15. References below point to that revision.
| Strategy | Unit starts from | Unit integration | Final delivery PR |
|---|---|---|---|
intent-pr |
Intent branch | Engine merges unit into intent branch | Intent → base |
pr-per-unit |
Intent branch | Reviewed unit PR → intent branch | Intent → base |
Proposed pr-per-unit-to-base |
Fresh target-branch tip after dependencies are delivered | Reviewed unit PR → base | None |
The existing PR-per-unit path already has useful machinery: draft PRs, dependency waits, authenticated feedback, per-repository outcomes, durable callbacks, and recovery. Reuse those owners and records. Today, however, lane initialization, reconciliation, PR creation, and workspace refresh explicitly use the intent branch; final orchestration still opens the intent PR. [1–4]
Example: A is a shared foundation, B and C depend on A, and D depends on both B and C.
flowchart TD
A["A: branch from main → review → merge"] --> B["B: branch from updated main → review → merge"]
A --> C["C: branch from updated main → review → merge"]
B --> D["D: starts after B and C are verified on main"]
C --> D
B and C can work concurrently within the existing parallelism limit. D is not started speculatively on either unmerged branch. A unit with no dependency can start independently, subject to the workflow's required gates.
2. Configuration and branch lifecycle
- Add an explicit strategy value to the shared registry, platform/project validation, execution snapshot, API types, settings UI, and user documentation. Keep existing defaults.
- Resolve and snapshot the repository identity and target branch name at execution start. Capture a fresh target commit SHA when each new unit starts. These are different lifetimes.
- After dependency verification, fetch the target and create the unit branch from its observed tip. Record the starting SHA and dependency delivery identities. Recheck that required dependency results are contained in that fetched target before launching work.
- Keep section/unit/attempt ownership explicit. A retry or restored session resumes its existing branch and baseline; it must not reset unpublished work to today's
main. - Use the existing engine-owned Git and credential path. This strategy does not grant agents repository credentials or permission to push directly to the target.
- An absent, renamed, or unexpectedly retargeted base blocks delivery with an actionable error. Existing PR helpers can fall back to a repository's default branch; this mode must not silently change its pinned destination. [5]
The first release should require an existing target branch. Empty-repository bootstrap needs a separately defined path that respects repository protections.
3. What a deliverable unit must contain
A unit must be reviewable and safe to integrate on its own: implementation, relevant tests, documentation, compatibility changes, and any required feature flag belong together.
The current execution keys are section-specific unit lanes. A methodology unit appearing in several parallel sections is not automatically one complete code-delivery increment. The workflow needs an explicit publication boundary after all required stages for that increment. Incompatible workflow layouts should be rejected during preflight rather than publish an unfinished design or code fragment. [6]
Shared work needs an owner:
- Requirements/design artifacts can remain canonical in the existing artifact graph and be supplied to lanes as pinned context.
- Repository changes made before unit work—shared code, configuration, schemas, checked-in documents—must be assigned to an explicit foundation unit or another named delivery unit. Merge that dependency first when later units need its files.
- A lane must not silently inherit every unmerged intent-branch commit. That would recreate the aggregate feature inside each unit PR.
- Shared stages after unit delivery run against a recorded target revision. If they generate repository changes, publish those through an explicit follow-up/integration unit PR. They must not leave changes stranded on an intent branch or turn into a hidden rollup PR.
The engine currently commits stage output to the workspace branch, so replacing only lane branch creation would leave shared output outside this new delivery path. [1,7]
4. Human gates must precede the publication they govern
This is a required design change. Today the walking-skeleton and gated-batch review loops execute after their lanes have merged into the intent branch; they can request another revision there. With direct target delivery, that ordering would mean the work is already on main before the review can reject it. [8]
For the new strategy:
- Preserve all required stage validations, sensors, and selected human gates.
- Complete the skeleton publication review before its PR becomes ready for merge; a requested revision updates the unmerged unit.
- For gated batches, collect the required batch review before making that batch's PRs ready. Dependencies still wait for actual merges, and individual PR merges remain non-atomic.
- Leave existing autonomy choices intact. Do not introduce a new blanket approval gate or named-reviewer policy.
- Required checks that determine whether an individual unit may enter
mainmust run before that merge. Later whole-feature checks remain valuable, but their failure requires a corrective PR for already delivered work.
Repository protections and authorized maintainers still govern actual merging. Draft status is not an authorization boundary: if somebody bypasses the intended order and merges early, record the external delivery and pause for reconciliation; do not pretend the merge did not happen or silently count the gate as satisfied.
5. Define verified delivery, including squash and rebase
A PR being ready, approved, mergeable, queued, or reported as closed does not satisfy a unit dependency. Verify provider-confirmed merge into the expected repository/target, bind it to the accepted unit revision, and record the resulting commit on that target.
The current integration and repair paths test whether readyHeadSha is an ancestor of the intent branch. Merely changing the descendant branch to main is insufficient: squash and rebase merges can deliver the change without preserving the original source commit. The normalized GitHub status currently does not expose its merge result SHA. [3,5,9]
A local real-Git fixture, with an unrelated advance on main, confirmed:
| Merge method | Unit content delivered | Original reviewed head is an ancestor of target |
|---|---|---|
| Merge commit | Yes | Yes |
| Squash | Yes | No |
| Rebase then fast-forward | Yes | No |
GitHub documents that, after merge, merge_commit_sha identifies the merge commit, squash commit, or commit to which the base was updated for a rebase merge. Before merge it can identify a test merge commit, so its mere presence is not delivery evidence. [10]
Extend existing unit-PR persistence with sufficient provider-backed delivery evidence: repository and target identity, PR identity, unit/section and plan revision, accepted source head, resulting target commit, and execution/attempt ownership. This is an extension of the existing source of scheduling truth, not a second state store.
Verification must handle:
- Merge, squash, and rebase semantics for each enabled provider; do not infer a merge method from an unreliable field.
- An edited source head invalidating readiness and applicable checks.
- Wrong-target merges, PR retargeting, missing evidence, closed-unmerged PRs, and temporarily unavailable provider reads.
- Merge queues: queued is still waiting; verify the actual landed result.
- Duplicate callbacks and a crash after provider merge but before persistence.
Missing or ambiguous proof leaves the dependency blocked. Commit ancestry demonstrates history inclusion, not that a later commit has preserved the behavior: a subsequent revert can retain ancestry. Known reversions or failed integration checks need a repair decision, not a claim of semantic correctness from Git alone.
6. Scheduling, target movement, and multiple repositories
Preserve DAG scheduling: a dependent starts only after every required predecessor has a verified delivery outcome. Continue releasing compute while waiting for reviews and use the existing durable wakeup mechanism.
Independent intents and human PRs can advance main. Refresh/reconcile a unit branch when needed and rerun affected checks. Use provider-required checks and merge-queue rules; do not create an endless refresh cycle simply because an unrelated commit landed. The current integration lock is held across a unit's integration loop, so it also needs review before claiming independent units can remain ready concurrently. An execution-local lock cannot serialize all writers to main. [3]
For a unit spanning repositories, all required repository changes must be delivered before its dependents start. An unchanged repository is neutral only after a successful no-change assessment; a missing branch or provider error is not a no-op.
Cross-repository delivery is not atomic. If one PR merges and another fails or closes, retain the delivered result, report partial delivery, and block dependents. APIs and migrations must tolerate the intermediate combination. If multi-repository qualification is deferred from the first release, reject that configuration explicitly for this strategy.
7. Recovery, completion, and tracker behavior
Delivered work is durable history. Cancellation, repair, or rewind cannot remove a merge from main.
- Preserve verified delivered units and resume unresolved work. Retain delivery evidence even after branch deletion.
- A revision to an already delivered unit creates an explicit corrective attempt/PR. Do not reopen a merged PR or silently replay a published unit under its old identity.
- Reverting delivered work requires an ordinary reviewed revert PR and dependency reassessment. No automatic rollback or target-branch rewrite.
- Apply current ownership and plan-revision fences to feedback, callbacks, recovery, and delivery writes.
Execution completion needs a complete accounting of the selected plan: required units, shared stages, required gates, repository outcomes, and any explicitly accepted scope omissions. Partial delivery must remain visible; an accepted omission must not masquerade as the omitted unit having merged.
Skip final intent-PR publication for this strategy. Extend existing delivery state and tracker synchronization to consume the complete set of unit deliveries, including explicit foundation/follow-up units. Intermediate unit PRs reference the parent issue without Closes/Fixes keywords. Close the parent only when the complete required scope and final checks satisfy the existing closure policy. A unit may close its own explicitly mapped child issue.
Today final PR publication supplies the tracker delivery list, and the synchronizer closes the source issue once that list is merged. Supplying only the first unit PR would close the parent prematurely. Handle the zero-change outcome explicitly as well; do not fabricate an empty PR just to trigger completion. [4,11]
The UI should distinguish building, awaiting gate/review, awaiting merge, delivered to the configured branch, blocked, and partially delivered. Show each unit's PR and why a dependent is waiting. Do not label an intent-branch integration as delivery to main in the existing strategies.
8. Side effects and mitigations
| Consequence | Required response |
|---|---|
| Partial features can ship before the intent finishes | Use independently safe increments, feature flags where appropriate, and backward-compatible API/schema changes. |
| The feature no longer has one atomic merge or rollback | Preserve a delivery ledger and plan corrective/revert PRs explicitly. Keep the aggregate strategy for features that need its boundary. |
| More PRs, CI runs, and review notifications | Keep units meaningful, bound parallelism, and expose dependency/review waiting time. Smaller PRs trade aggregation for coordination. |
| Long dependency chains wait on humans | Show the critical path; extract genuinely shared prerequisites early without inventing dependencies between independent units. |
Shared files and active main create conflicts |
Assign change ownership, reconcile narrowly, rerun affected checks, and respect merge queues. |
| Whole-feature tests may fail after earlier units landed | Move publication-critical checks earlier; retain final integration checks and use explicit repair work for later discoveries. |
| Cross-repository merges/deployments can be temporarily inconsistent | Use compatible intermediate states and explicit partial-delivery recovery; a Git merge does not prove deployment. |
| Rewind and plan edits occur after external effects | Keep published history immutable and require a new delivery attempt where changes are needed. |
9. Small-PR implementation sequence
Implementation tracker — 13 focused PRs, merged individually into main. All items below are linked GitHub sub-issues of this RFC. The numbered order is a practical one-person sequence; the dependency column lists the actual prerequisites.
| Order | Sub-issue / PR outcome | Depends on |
|---|---|---|
| 1 | #555 — Define the publication contract and validate supported workflows | None |
| 2 | #556 — Verify GitHub unit delivery across merge, squash and rebase | #555 |
| 3 | #557 — Create and resume unit branches from pinned base revisions | #555 |
| 4 | #558 — Assign shared repository output to explicit delivery units | #555, #557 |
| 5 | #559 — Complete required skeleton and batch reviews before PR readiness | #555, #558 |
| 6 | #560 — Publish and observe individual unit PRs against the base branch | #556, #557, #558, #559 |
| 7 | #561 — Start dependent units only after verified base delivery | #560 |
| 8 | #562 — Preserve delivered units across retry, cancellation and rewind | #560, #561 |
| 9 | #563 — Complete intents from the full unit delivery set without a rollup PR | #558, #559, #561, #562 |
| 10 | #564 — Close the parent tracker only after complete unit delivery | #563 |
| 11 | #565 — Show unit delivery status and dependency blockers in the intent UI | #561, #562, #563 |
| 12 | #566 — Expose capability-gated strategy settings and operating guidance | #563, #564, #565 |
| 13 | #567 — Qualify the supported delivery flow and enable the opt-in capability | #566 |
Start with #555. Settle and encode the publication boundary, shared-output ownership rule, required gate placement, and initially supported provider/repository/workflow matrix. GitHub first, an existing base branch, and explicit foundation/follow-up units remain recommendations until that issue records the decisions. The breakdown does not approve new defaults or broaden merge authority.
How to keep the PRs small
- Each child defines one outcome, acceptance criteria, tests, starting points and explicit exclusions. Merge its PR directly into
main; start dependent work from updatedmain. There is no aggregate feature branch or final rollup PR. - The provider-evidence and lane-branch children can proceed independently after the contract; shared-file ownership, publication gates, unit publication, and dependency release are separate review boundaries.
- Keep the new capability disabled while pieces land. Each earlier PR must preserve the existing strategies and be safe to merge with its new behavior dormant; ordinary API requests must not bypass admission.
- Every implementation child owns its focused tests, necessary API/runtime/infrastructure wiring, and relevant documentation. [Unit PRs] Qualify the supported delivery flow and enable the opt-in capability #567 owns bounded integrated qualification and enablement, not accumulated implementation, deferred hardening or a large final integration patch. Fix a discovered defect in a focused PR under its owning child before enabling.
- If a child grows beyond its stated outcome, split it before implementation. Sharing a Lambda file does not justify combining unrelated children.
- Preserve old durable histories, captured settings and run/attempt ownership throughout; never expose a partially implemented strategy to in-flight executions.
Existing work and scope boundaries
- Prevent incomplete intents from reaching success and publication #534, Track final delivery and safely retry pull request publication #537 and Audit terminal intent completion with bounded read-only checks #539 were still open when this breakdown was created. [Unit PRs] Preserve delivered units across retry, cancellation and rewind #562 and [Unit PRs] Complete intents from the full unit delivery set without a rollup PR #563 must reconcile their recovery/completion contracts with the resulting work on
main, without building parallel versions or assuming unmerged branch code is present. - Additional provider adapters, empty-repository bootstrap, speculative stacked branches, automatic feature decomposition, generic artifact synchronization and automatic rollback are outside these children. If the first-release scope requires an additional adapter or workflow mechanism, add a focused prerequisite child before enabling it.
- Multi-repository support and external handoff compatibility are explicit decisions in [Unit PRs] Define the publication contract and validate supported workflows #555. An excluded configuration must fail admission; a supported configuration needs its applicable partial-delivery/recovery tests and qualification.
- The implementation planning baseline is
mainatb5d68d5d2f12292d56a21aab917e4d8f9538aa0b(2026-10-15). The change since the RFC's investigation baseline is the nested-Lambda CI build fix, with no change to the delivery/gate paths used for this decomposition. Recheck current main before each child.
The original design, side effects and open questions remain below/above as RFC context; this linked sequence replaces the earlier nine-row outline.
10. Related work and investigation limits
- Prevent incomplete intents from reaching success and publication #534 proposes stronger unit completion and reviewed recovery.
- Track final delivery and safely retry pull request publication #537 proposes explicit final delivery state and publication retry.
- Audit terminal intent completion with bounded read-only checks #539 proposes final completion guards and bounded consistency auditing.
- Prevent durable PR waits from exhausting execution operation limits #334 / fix: make durable PR waits callback-driven #335 cover durable PR waits; reuse the callback architecture.
- Feat: workflow handoff (external code-generation) #460 proposes external code-generation handoff; that path must receive the same assigned branch and pinned baseline, or be explicitly unsupported initially.
- [RFC]: Autonomous Tracker-Driven Intent Execution #415 discusses autonomous tracker-driven execution; choosing this strategy must not imply automatic approval or merge authority.
At investigation time, #534, #537, #539, and #460 were open. Their descriptions were checked for overlap; they were not treated as merged implementation or independently validated here.
This investigation traced repository source, read provider documentation, and ran the small Git ancestry fixture above. It did not implement the strategy, run platform suites, change repository protections, deploy, or perform credentialed provider/AgentCore end-to-end validation.
Alternatives considered
- Keep PR per unit into the intent branch. Useful when the feature needs an aggregate acceptance boundary, but retains the large final delivery diff.
- Split the feature into several independent intents. Lower implementation cost and viable today when each increment can carry its own planning context. It moves cross-intent dependencies and completion tracking to the operator.
- Stack PRs on other unmerged unit branches. Starts dependents earlier, but adds retargeting/rebase complexity and differs from the requested rule that prerequisites reach
mainfirst. - Periodically merge an intent branch into
main. Reduces delivery frequency without establishing clear per-unit ownership; risks mixed unrelated changes in each delivery. - Replace the existing PR-per-unit strategy globally. Rejected: it changes review timing, visibility, and recovery semantics for users and in-flight executions.
Breaking changes
No intentional change to existing strategies or defaults. This is opt-in for new executions.
The new mode deliberately changes the delivery contract: incremental target-branch merges, no final rollup, and no rollback through ordinary rewind. Existing executions keep their captured policy. An execution must not switch strategy after starting.
Additive configuration and provider/status fields still require a coordinated rollout. Current normalization can fall back to intent-pr for unknown values. Deploy compatible readers, source-control adapters, runtime/orchestrator, and APIs before exposing or accepting the new mode; version-gate new durable behavior and cover frozen-history replay. Disabling new starts must not strand executions already using it.
Open questions
- Confirm the name
pr-per-unit-to-base/ “Unit PRs to base branch”. - Which workflow layouts define a complete publication increment when a unit appears across several parallel sections?
- Adopt explicit foundation/follow-up units for repository changes outside the main unit sections, with graph-only artifacts remaining graph-owned?
- Start with GitHub and an existing target branch? Qualify multiple repositories immediately or reject them until a follow-up?
- Which integration checks must become pre-merge checks, and which are explicitly post-delivery acceptance checks for a given workflow?
- How should accepted partial scope affect parent tracker closure, consistent with the completion work in Prevent incomplete intents from reaching success and publication #534/Audit terminal intent completion with bounded read-only checks #539?
Investigation references
- Documented Git, PR, and stage lifecycle.
- Strategy registry and capabilities; lane initialization.
- Unit PR creation, merge verification, dependency waiting, integration lock.
- Final PR publication and tracker handoff; final PR body and branch handling.
- GitHub base fallback; normalized PR status.
- Section/unit and unit-PR record keys.
- Stage output commit/push.
- Post-integration skeleton review; post-integration batch review.
- Recovery merge verification.
- GitHub REST: Get a pull request, merge result SHA semantics.
- Tracker merge waiting and source issue closure.
Activity