Skip to content

Honor repository branch-name policy before builder PR creation - #970

Closed
devin-ai-integration[bot] wants to merge 6 commits into
mainfrom
devin/865-branch-policy
Closed

Honor repository branch-name policy before builder PR creation#970
devin-ai-integration[bot] wants to merge 6 commits into
mainfrom
devin/865-branch-policy

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #865

  • New code_mower/branch_policy.py: repositories[].delivery_policy.branch_template is a per-repository branch-naming contract separate from builder_identity.branch_prefixes (provenance). compile_template(template) -> BranchPolicy(template, pattern, example, configured), resolve_branch(policy, lane=, issue_key=, issue_number=, slug=, work_type=, repository=), validate_branch(policy, branch). Only {lane} {issue_key} {issue_number} {slug} {work_type} {repo_name} are accepted and a template must contain {issue_key} or {issue_number}. {issue_key} falls back to the GitHub issue number; an empty slug drops itself and its leading separator (fix/{issue_key}-{slug} -> fix/907). No policy configured -> default_policy() ({lane}/{issue_key}-{slug}, configured=False), i.e. the provider-prefix convention is unchanged.
  • config.validate_config validates delivery_policy (only branch_template, compiled) and deduplicates repository slugs case-insensitively, matching the case-insensitive policy lookup; branch_policy.policies_by_repository(config) raises on such a collision instead of letting one entry shadow another.
  • Hosted Devin seam (devin_work_orders.py): WorkOrder.from_manifest(..., config=) (or an explicit branch_policy=; exactly one is required, omission raises branch_policy_required) applies the configured repository policy and rejects a nonconforming branch with RemoteError("branch_policy_mismatch: ...") before any provider create. WorkOrder.repository_policy(config, repo) and WorkOrder.resolve_branch(policy, lane=, issue=, work_item=, slug=) are the maintained dispatcher path: the bound tracker key (e.g. a Jira issue key) becomes {issue_key}, so a Jira-keyed order resolves fix/MB-9506-nv-accessible-label on the first attempt. Unconfigured/default policies leave the order, its _fields, binding hash, and prompt byte-identical to before.
  • Generated local runner seam (run_mac_lane.sh, all three synchronized copies): init embeds __LANE_MAC_RUNNER_BRANCH_POLICY_JSON__ and __LANE_MAC_RUNNER_BUILDER_AUTHORS_JSON__. For an issue target with a policy the runner resolves the exact branch before the provider runs and tells the provider the template/pattern/example plus that exact branch.
  • Provenance is decided by a shared jq predicate (lane_provenance): configured builder labels and the authenticated PR author are mapped to lanes; at least one must map to the current lane and none may map to another lane (conflicts fail closed). Delivery-policy compliance is never a provenance signal. The predicate applies to explicit pr: targets, automatic fix-round selection, and delivery-snapshot discovery. Snapshot discovery additionally requires a same-repository head, the exact pre-resolved branch (lane prefix only when no policy is configured), the closing-issue reference, and exactly one candidate (multiple -> failed lookup, not a guess).
  • Pre-push guard: allowed_pattern is gone. allowed_branch carries the exact resolved branch (authority repo_policy_branch); lane prefixes, the verified explicit target branch, and validated handoffs are unchanged. A regex can no longer grant write authority to any other policy-matching branch.
  • Documentation: docs/github-setup.md example, docs/devin-work-orders.md dispatcher example now passes config and resolves the branch through WorkOrder, commented delivery_policy stanza in code-mower.example.yml.

Assumptions: the local runner derives {slug} from the issue title after slugification ([a-z0-9-], max 48 chars); {work_type} renders as fix in the runner. Existing fake gh fixtures that model "this run opened its PR" now carry headRepository, labels, and author because a PR without provenance is (correctly) no longer attributable to a lane. tests/test_devin_work_orders.py passes an unconfigured config where it previously relied on the omitted-policy default.

Validation

  • python scripts/privacy_scan.py, python -m ruff check src tests, python -m compileall -q src scripts, python scripts/guard_package_workflows.py, python -m code_mower.migration release-readiness --json: pass
  • python -m pytest tests: 3634 passed, 19 skipped
  • templates/lanes/run_mac_lane.sh and src/code_mower/templates/lanes/run_mac_lane.sh are byte-identical; tools/lanes/run_mac_lane.sh differs only in generated substitutions.
  • Regression coverage added: cross-builder, human, conflicting label/author, conflicting labels, fork-head, other-policy-branch and lane-prefix-not-policy PRs are rejected for explicit targets, automatic selection, and delivery snapshots; label-alone and author-alone each suffice; two lane candidates fail closed; only the exact resolved branch (not other policy-matching names, and not an allowed_pattern in the guard config) is writable; case-insensitive duplicate repository slugs are a config error and are rejected by WorkOrder.repository_policy; omitting both config and branch_policy is rejected; Jira-keyed orders resolve a conforming branch through the maintained WorkOrder path.

Risk / Rollback

  • Opt-in: repositories without delivery_policy behave as before, except that WorkOrder.from_manifest now requires config= or branch_policy= (a dispatcher that omitted both must pass its loaded config). Revert the two commits to roll back.

Data Or Secret Exposure

  • This change does not add source, raw diffs, raw transcripts, raw provider output, tokens, or machine-specific paths to public artifacts.

Link to Devin session: https://app.devin.ai/sessions/60ec1193b3d340459132d91e5df39f9d
Open in Devin Desktop: https://app.devin.ai/desktop/session/60ec1193b3d340459132d91e5df39f9d?variant=devin

Add repositories[].delivery_policy.branch_template, resolved and validated
independently of builder_identity.branch_prefixes, and wire it into the
hosted Devin work-order seam and the generated local lane runner.

Closes #865

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@jeffhuber

Copy link
Copy Markdown
Contributor

Codex audit (merge-authority lane)

Head SHA: 88614178c5cf58d4068424d7214e13c9e131410b
Findings: P0=0, P1=1, P2=1, P3=0 (blocker policy: any P0/P1/P2 → BLOCKED)

Codex Audit: BLOCKED

Summary:

Branch-policy compliance is conflated with builder ownership, breaking single-writer enforcement and risking misattributed delivery outcomes.

Findings:

  • [P1] Require lane ownership independently of branch-policy compliance -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-xnib5_i6/wt/src/code_mower/templates/lanes/run_mac_lane.sh:453
    Finding ID: codex:06679f6468b9d819d49e
    With a shared template such as fix/{issue_key}-{slug}, every conforming PR is treated as owned by the current lane without checking its builder label or author. Targeting another builder's PR skips recovery-handoff validation, and pattern-based pre-push authorization permits writing that branch. Determine ownership from builder provenance and restrict writes to the authorized branch. Apply the correction to all runner copies.
  • [P2] Filter delivery snapshots by builder provenance -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-xnib5_i6/wt/src/code_mower/templates/lanes/run_mac_lane.sh:548
    Finding ID: codex:f3604f68b622cf4b3ea3
    With a shared repository template, lane_pr_for_issue selects any conforming PR closing the issue, including another builder's or a human's PR. The lookup does not request labels or author information, so capture_target_state can attribute an unrelated PR's creation or head movement to the current run, incorrectly report delivery, or select it instead of the lane's actual PR. Fetch and filter by lane provenance before choosing the PR, and update all runner copies.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Devin is currently unreachable - the session may have died.

View session

@jeffhuber

Copy link
Copy Markdown
Contributor

Claude audit (merge-authority lane)

Head SHA: 88614178c5cf58d4068424d7214e13c9e131410b
Findings: P0=0, P1=0, P2=0, P3=2 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

Branch-policy feature (template compilation, config validation, hosted work-order integration, and generated Mac-lane-runner enforcement) is well-scoped and heavily tested, including an end-to-end runner execution test. No P0/P1/P2 correctness, security, or contract-breaking issues found; only minor non-blocking observations.

Findings:

  • [P3] Malformed-pattern sanity check does not assert the boolean result -- tools/lanes/run_mac_lane.sh:90
    Finding ID: claude:cd47a0541d5d04b22429
    The 'fail closed on a malformed pattern' guard runs jq -n ... '$example | test(...)' and only checks jq's process exit code, but jq exits 0 whether test() evaluates to true or false (no -e flag). It only catches a regex that fails to compile, not a pattern/example that legitimately mismatch. Low impact since the pattern/example pair is generated and pre-validated by branch_policy.compile_template() in Python before being embedded, so this shell-side check is effectively unreachable in practice; consider jq -ne ... if real enforcement here is intended.
  • [P3] Lane-prefix branch ownership still recognized even when a repository delivery_policy is configured -- src/code_mower/templates/lanes/run_mac_lane.sh:140
    Finding ID: claude:d2ff1f48310598ea1e1b
    has_lane_prefix/allowed_pattern checks in the fix/PR-ownership lookups and the pre-push guard are combined with OR, so a branch like codex/123-x is still treated as lane-owned and pushable even on a repository that only advertises a fix/{issue_key}-{slug} delivery_policy. This appears to be intentional (provenance vs. acceptance are documented as separate contracts, and it preserves compatibility with pre-existing lane-prefixed PRs), but worth confirming that a policy-configured repo is not expected to strictly reject lane-prefixed branches at push time.

…rity

A branch that satisfies repositories[].delivery_policy is valid for every builder and for humans, so matching it proves nothing about provenance. The runner now decides ownership from configured builder labels plus the authenticated PR author (at least one current-lane signal, none mapping elsewhere) for explicit targets, automatic fix selection, and delivery snapshots; snapshots also require a same-repository head, the exact pre-resolved branch, and exactly one candidate. The pre-push guard authorizes the exact resolved branch instead of the policy regex.

Repository slugs are deduplicated case-insensitively to match policy lookup, and WorkOrder.from_manifest requires the loaded config (or an explicit policy) so a hosted dispatcher cannot skip a configured policy by omission; WorkOrder.resolve_branch covers the tracker-key path.

Co-Authored-By: bot_apk <apk@cognition.ai>
@jeffhuber

Copy link
Copy Markdown
Contributor

Codex audit (merge-authority lane)

Head SHA: 85f2e21a1e9bd9d8d2becff855d2815f655df620
Findings: P0=0, P1=0, P2=2, P3=0 (blocker policy: any P0/P1/P2 → BLOCKED)

Codex Audit: BLOCKED

Summary:

The runner inconsistently enforces branch restrictions, and its provenance map omits identities needed to detect cross-builder ownership conflicts.

Findings:

  • [P2] Restrict policy-enabled pushes to the resolved branch -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-ls1151ey/wt/src/code_mower/templates/lanes/run_mac_lane.sh:379
    Finding ID: codex:9804d1014eb2698a40b4
    When a repository configures a template such as fix/{issue_key}-{slug}, the guard still includes the lane's ordinary prefixes, and its authorization logic accepts those before checking allowed_branch. A builder can therefore push a nonconforming provider-prefixed branch despite the generated prompt promising that every other branch is rejected. Disable prefix-based authorization for policy-bound issue runs in both runner templates and the checked-in runner.
  • [P2] Preserve nonlocal builder identities for conflict detection -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-ls1151ey/wt/src/code_mower/init.py:1146
    Finding ID: codex:ff3bd7c2e3123abd4b64
    Filtering authors to mac_lanes prevents the new provenance check from detecting conflicting ownership by configured builders outside the local runner. For example, a policy-conforming PR labeled builder:codex but authored by configured cursor[bot] is treated as exclusively Codex-owned when Cursor is absent from mac_lanes, allowing a fix run without a handoff. Include all configured builder authors in the conflict-detection map, and likewise retain nonlocal builder labels for that check; execution eligibility should be filtered separately.

@jeffhuber

Copy link
Copy Markdown
Contributor

Claude audit (merge-authority lane)

Head SHA: 85f2e21a1e9bd9d8d2becff855d2815f655df620
Findings: P0=0, P1=0, P2=0, P3=1 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

PR #970 adds a repository branch-name policy contract (branch_policy.py), threads it through Devin hosted work orders (devin_work_orders.py), config validation (config.py), and the generated/local Mac lane runner script (three synced copies). The change is extensively covered by new tests (test_branch_policy.py, updates to test_devin_builder_lane.py, test_devin_work_orders.py, test_init_build_loop.py, test_lane_delivery_contract.py) including end-to-end subprocess fixtures for the generated runner, pre-push guard authority, and provenance/ownership edge cases (conflicting labels, forks, ambiguous candidates). Core invariants (template validation, branch resolution, case-insensitive duplicate-slug rejection, hosted work-order binding requiring an explicit config or branch_policy, pattern portability to jq) are each backed by targeted tests. The one behavior that looked at first like a bypass — the pre-push guard still allowing a lane's legacy branch prefix even when a repository delivery_policy is configured — is a deliberate, explicitly tested design choice (test_only_the_exact_resolved_policy_branch_is_writable_without_a_lane_prefix), not an oversight, so it is not flagged as blocking. No P0/P1/P2 correctness, security, or data-loss issues were found. Independence guard: head branch is devin/865-branch-policy (not claude/*), so this is a normal, applicable audit, not a Claude-authored PR.

Findings:

  • [P3] policy_for_repository() silently shadows duplicate-slug configs instead of failing closed -- src/code_mower/branch_policy.py:121
    Finding ID: claude:6ba1347cb514d6d861d3
    policy_for_repository() returns the first repositories[] entry whose slug matches case-insensitively and never checks for a second colliding entry, unlike policies_by_repository()/WorkOrder.repository_policy() which raise BranchPolicyError on a case-insensitive duplicate slug. Since policy_for_repository is a documented public entry point (referenced in docs/devin-work-orders.md's example), an external dispatcher calling it directly with a config containing two case-variant slugs (e.g. "owner/repo" and "Owner/Repo") would silently apply whichever policy appears first instead of failing closed the way the rest of the module intends. Not exercised by the current production call paths (which all use the duplicate-checking helpers), so this is non-blocking, but worth aligning for API consistency.

…ovenance

A policy-enabled issue build now authorizes only the resolved branch:
allowed_prefixes is emptied while allowed_branch is set and the guard's
lane_prefix path requires that no exact policy branch exists.

Provenance conflict detection maps labels (including aliases and
builder_identity labels) and authenticated authors for every configured
builder lane to its lane, so a PR carrying a nonlocal builder's signal is a
conflict rather than unowned. Execution eligibility remains mac_lanes.

Applied to all synchronized runner copies with regression tests.

Co-Authored-By: bot_apk <apk@cognition.ai>
The runner now checks the rendered policy branch with the same
conservative git-check-ref-format subset as branch_policy.is_valid_ref
(plus git check-ref-format --branch) before installing the pre-push guard
or starting a provider. A repository named .github with template
{repo_name}/{issue_number} renders .github/12, which matches the policy
pattern but is not a valid branch; the run now fails before dispatch.

Applied to all synchronized runner copies with regression tests that
exercise the .github case end to end and compare the shell and Python
validators over the same inputs.

Co-Authored-By: bot_apk <apk@cognition.ai>
@jeffhuber

Copy link
Copy Markdown
Contributor

Codex audit (merge-authority lane)

Head SHA: 7bfb7239e00d91b8f7f3ec6b4e4f2767ae971594
Findings: P0=0, P1=0, P2=2, P3=0 (blocker policy: any P0/P1/P2 → BLOCKED)

Codex Audit: BLOCKED

Summary:

Policy-named branches cannot use explicit recovery handoffs, and transient title lookup failures can change branch identity and cause duplicate delivery. Both issues affect the generated runner and its mirrored copies.

Findings:

  • [P2] Support explicit recovery handoffs for policy-named branches -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-uct8u_qc/wt/src/code_mower/templates/lanes/run_mac_lane.sh:487
    Finding ID: codex:9a21a642871f5ca3a317
    When a repository uses fix/{issue_key}-{slug}, a PR owned by another lane enters the handoff path, but that path passes only provider prefixes to lane_delivery.validate_handoff. The validator rejects target branches lacking the source lane's prefix, preventing explicit handoffs even with the correct expected head. Extend validation to verify the source lane's provenance for the exact policy branch while preserving existing head checks.
  • [P2] Fail branch resolution when the title lookup fails -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-uct8u_qc/wt/src/code_mower/templates/lanes/run_mac_lane.sh:588
    Finding ID: codex:414e45c3daa293c04a1f
    If the GitHub title lookup transiently fails, || true treats the failure as an empty title and resolves a different branch, such as fix/12 instead of fix/12-nv-accessible-label. Because lane_pr_for_issue matches only the exact resolved branch, it can miss an existing PR and instruct the provider to open a duplicate. Retry the lookup or abort before running the provider; only a successfully retrieved title should determine the slug.

@jeffhuber

Copy link
Copy Markdown
Contributor

Claude audit (merge-authority lane)

Head SHA: 7bfb7239e00d91b8f7f3ec6b4e4f2767ae971594
Findings: P0=0, P1=0, P2=0, P3=0 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

Reviewed the branch-name-policy feature (branch_policy.py, config validation, WorkOrder integration, and the mirrored bash logic in the generated/repo run_mac_lane.sh templates). The Python resolver/validator and its bash mirror (is_valid_ref, pattern matching, provenance checks) are logically consistent with each other and with the extensive new test suite (test_branch_policy.py plus updates across test_devin_builder_lane.py, test_devin_work_orders.py, test_init_build_loop.py, test_lane_delivery_contract.py), which specifically exercises the security-relevant edge cases: fork heads, conflicting builder labels/authors, multiple PR candidates, unconfigured repos, case-insensitive slug dedup, and ref-validity parity between the Python and shell implementations. The single-writer pre-push guard correctly narrows write authority to the exact resolved branch when a repository delivery_policy is configured, and falls back to lane-prefix authority otherwise. No correctness, security, or data-loss blockers were found; the WorkOrder.from_manifest signature change (now requiring config or branch_policy) is a documented, intentional breaking change for external dispatchers, not an oversight. Head branch is devin/865-branch-policy (Devin-authored), so the Claude-audit independence guard does not apply.

Findings: none.

A failed or empty gh issue title lookup no longer degrades into an empty
slug: the runner aborts before branch resolution, guard installation, or
any provider start, so a transient GitHub failure cannot resolve a
different branch, miss the PR an earlier run opened, and deliver twice.
Applied to all three synchronized run_mac_lane.sh copies with a
regression test for both the failed and the empty lookup.

The explicit-handoff refusal for a repository-policy-named branch now
points at #962, which owns provenance-aware
handoff; the refusal itself is unchanged and stays fail-closed.

Co-Authored-By: bot_apk <apk@cognition.ai>
@jeffhuber

Copy link
Copy Markdown
Contributor

Codex audit (merge-authority lane)

Head SHA: 08287175e8b020f54016f8f2e123f5a898d9ddab

Could not validate a Codex structured verdict artifact. The CLI may have produced no review, the structured-output pass may have failed, or the verdict format may have drifted. Requeuing for re-review.

@jeffhuber

Copy link
Copy Markdown
Contributor

Claude audit (merge-authority lane)

Head SHA: 08287175e8b020f54016f8f2e123f5a898d9ddab
Findings: P0=0, P1=0, P2=0, P3=2 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

Repository branch-name policy feature (branch_policy.py + config validation + Devin work-order integration + generated/committed run_mac_lane.sh runner) is well-tested and fail-closed. Python resolver/validator, jq-based provenance queries, and bash ref validation were cross-checked and are consistent; provenance separation (label/author, never branch name alone) correctly prevents an attacker from hijacking builder write authority via a policy-conforming branch name. No P0/P1/P2 correctness or security blockers found.

Findings:

  • [P3] unauthorized decision marker -- (PR comment metadata):1
    Finding ID: claude:a2564680745d863956c5
    The trusted decision registry reports one CODE_MOWER_DECISION marker (author=jeffhuber, comment_id=5655689119) from a commenter without configured decision authority. Per doctrine this is reported as non-blocking and its payload is not honored.
  • [P3] branch_policy.policy_for_repository does not detect case-insensitive duplicate repository slugs -- src/code_mower/branch_policy.py:118
    Finding ID: claude:76c4de36af9b58bd7f9b
    policies_by_repository() and WorkOrder.repository_policy() correctly raise BranchPolicyError on case-insensitive duplicate repository slugs, but the standalone policy_for_repository() helper silently returns the first match without that check. It isn't on the enforced dispatch path today (dispatch goes through policies_by_repository), but if a future caller uses policy_for_repository() directly against an unvalidated config, a duplicate-slug misconfiguration could silently resolve to the wrong policy instead of failing closed.

Before the guard is installed or a provider starts, a policy-bound issue
run now inspects the resolved branch on origin. An existing branch is only
writable when every pull request attached to it carries this lane's
provenance; a foreign builder's or a human's pull request, a branch with no
attributable pull request, or a failed lookup refuses the run. The
delivery-snapshot filter can no longer make a foreign PR look absent and
grant authority over its branch. Cross-builder recovery of a policy-named
branch stays a fail-closed explicit handoff concern (#962).

In pull-request fix rounds on a repository with a configured branch policy,
the target head must match that policy; a lane prefix alone no longer
authorizes an off-policy branch, and the guard is installed for exactly the
validated target with the lane prefixes withheld. Repositories without a
policy keep the provider-prefix behavior.

Applied to all synchronized run_mac_lane.sh copies with regressions for a
foreign-builder branch, a human-owned pull request, an unattributed branch,
same-lane continuation, an off-policy prefixed fix target, the exact
policy-compliant target, and the no-policy prefix path.

Co-Authored-By: bot_apk <apk@cognition.ai>
@jeffhuber

Copy link
Copy Markdown
Contributor

Codex audit (merge-authority lane)

Head SHA: b9ef7e437c1c7f83de9e559f9659ff9e3457a42d
Findings: P0=0, P1=0, P2=1, P3=0 (blocker policy: any P0/P1/P2 → BLOCKED)

Codex Audit: BLOCKED

Summary:

Policy-based issue retries can lose track of an existing PR after a title change, allowing duplicate delivery instead of preserving the original branch.

Findings:

  • [P2] Preserve existing issue branches when the title changes -- /private/var/folders/f2/g9zqfdjx7z3ckcsx_f46htwm0000gn/T/codex-audit-3wh7nuv7/wt/src/code_mower/templates/lanes/run_mac_lane.sh:701
    Finding ID: codex:52b51726a2c8b37017c3
    When an issue using a {slug} policy is renamed and retried with --target issue:<n>, the runner resolves a new branch from the current title. This exact-name filter then hides the lane's existing PR linked to that issue, while the remote-branch ownership check also checks only the new name. The provider is consequently instructed to create a different branch, and a duplicate PR can be recorded as a successful delivery. Discover existing policy-compliant PRs by issue and provenance before resolving a fresh branch, then reuse the existing branch or refuse the ambiguous retry.

@jeffhuber

Copy link
Copy Markdown
Contributor

The hosted Devin qualification run is stopping here without merge. The exact-head Code Mower Codex audit at b9ef7e4 confirmed two remaining safety blockers: current branch ownership is not bound to the observed remote head SHA, and explicit handoff can still bypass a configured repository branch policy.

This PR required five bounded recovery sessions after the initial delivery. The provider is now suspended; its API rejected cancellation, and no further provider writes are authorized. Issue #865 remains open and will continue on a fresh Codex-owned branch and pull request so ownership and review evidence are unambiguous. This PR remains part of the public qualification evidence and is not counted as a successful Devin delivery.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Builder delivery: honor target repository branch-name policy before PR creation

1 participant