Skip to content

Move deterministic finalization from Codex into Code Converge #39

Description

@dapi

Summary

Make Code Converge itself own deterministic delivery orchestration after a clean review: commit/checkpoint handling, push, pull-request discovery or creation, and CI waiting. Codex should remain responsible for reasoning-heavy work such as review, code changes, and diagnosing or fixing failed CI, but it should no longer decide how to execute or classify deterministic Git/GitHub lifecycle operations.

This is one feature delivery unit. It requires a feature package under memory-bank/features/FT-<issue>/, explicit design, and an accepted ADR before implementation.

Problem

Finalization is currently delegated to a codex exec session. The agent is prompted to commit, push, create a change request, and ensure CI is green, then returns a structured verdict. This creates two classes of avoidable operational failure.

CI waiting is bounded by the Codex session rather than the workflow

In an observed run:

  • review converged after five cycles;
  • push and pull-request discovery succeeded;
  • three GitHub Actions checks were still pending;
  • gh pr checks --watch was interrupted after only a few minutes;
  • the finalizer returned:
{
"verdict": "FAILED",
"commit": "skipped",
"push": "success",
"change_request": "success",
"ci": "unknown"
}

Code Converge consequently reported an operational failure and exited 2. The checks later completed: two passed and one failed. Had Code Converge owned CI waiting, it could have detected the failure normally and entered the existing Fix CI path.

Increasing an agent prompt timeout is not sufficient. CI duration must be governed by Code Converge independently of model turns and Codex background-terminal limits.

Git worktree metadata can be outside the Codex writable workspace

For a linked worktree, the working tree and the shared Git metadata can live in different locations:

worktree: <worktree-root>
git-dir: <main-repository>/.git/worktrees/<worktree>
common: <main-repository>/.git

A Codex finalizer running in workspace-write can write the worktree but cannot write protected Git metadata. A push can therefore update the remote successfully but fail to update the local remote-tracking ref with an error such as:

cannot lock ref 'refs/remotes/origin/<branch>': Operation not permitted

This leaves misleading local output such as [ahead N] even though the remote branch and PR head already contain the pushed commit. The same Git command works in the operator shell because that shell is not running inside the Codex filesystem sandbox.

Granting the finalizer danger-full-access would work around the symptom but would unnecessarily give model-generated commands broad host write access.

Desired architecture

Adopt and record an ADR with the reusable rule:

Code Converge owns deterministic repository and delivery lifecycle orchestration. Codex owns reasoning, review, code modification, and diagnosis/remediation tasks whose commands cannot be fully predetermined.

The ADR must be accepted as a design prerequisite within this issue. A separate GitHub issue for the ADR is not required.

The intended responsibility boundary is:

ResponsibilityOwner
Inspect repository stateCode Converge
Create safe local checkpoint/commit when requiredCode Converge
Avoid empty or unsafe commitsCode Converge
Resolve push remote and branchCode Converge
PushCode Converge
Discover or create the pull requestCode Converge
Poll and classify applicable CICode Converge
Review changesCodex
Modify code to address findingsCodex
Diagnose and fix failed CICodex

Deterministic commands may still be executed as child processes such as git and gh; the requirement is that Code Converge constructs, runs, observes, retries, and classifies them rather than delegating those decisions to a Codex turn.

Required behavior

Publication

  • Finalization begins only after the existing clean-review gate.
  • Preserve the existing local-checkpoint safety contract and do not create empty commits.
  • Determine whether a commit is required without asking Codex.
  • Resolve the correct push remote and current branch deterministically.
  • Push from the Code Converge host process so linked-worktree Git metadata remains writable under the operator's normal permissions.
  • Treat remote publication and local tracking-ref state as separate observable outcomes; do not claim that a remote push failed merely because local tracking metadata could not be refreshed.
  • Reuse one matching open pull request or create one when required.
  • Fail actionably on ambiguous remote, branch, or pull-request identity.

The feature design must explicitly decide how pre-existing dirty worktree content is handled. It must not silently weaken the current checkpoint protections or commit unrelated user changes.

CI orchestration

  • Wait for applicable pull-request CI in Code Converge, not inside Codex.
  • Add a configurable CI timeout with a built-in default of 60 minutes.
  • The timeout starts from the point at which Code Converge begins waiting for the published revision.
  • Detect a failed applicable check as soon as possible and enter the existing CI_FAILED / Fix CI flow without waiting for unrelated long-running checks to finish.
  • Report success only after all applicable checks for the published revision have reached an accepted successful or skipped terminal state.
  • Treat absence of applicable CI as skipped according to an explicitly documented selection rule.
  • Ensure the observed checks belong to the exact published head revision so a stale run cannot produce a false success.
  • Handle transient GitHub/gh failures with bounded retries inside the same deadline; permanent authentication, authorization, identity, or protocol failures remain operational errors.
  • A deadline expiry must be reported explicitly as a CI timeout, not as generic agent finalization failure and not as red CI.
  • Ctrl-C must continue to cancel active child processes and exit 130.

Suggested public configuration surface, following existing precedence conventions:

--ci-timeout
CODE_CONVERGE_CI_TIMEOUT
ci-timeout
built-in default: 60m

The feature design must decide the exact event/status compatibility for timeout. The human output must name the timeout and elapsed limit. Machine-readable output must distinguish timeout from failed and from an unclassified unknown result.

CI remediation loop

  • A real CI failure invokes the existing Codex Fix CI stage.
  • After Codex changes the worktree, Code Converge resumes its existing review/checkpoint flow.
  • After review is clean, Code Converge republishes the new revision and waits for CI again.
  • CI timeout must not be passed to Fix CI as though tests had failed.
  • Existing maximum CI recovery limits remain effective.

Codex finalization contract

  • Remove publication and CI polling from the finalization prompt and structured result contract.
  • Determine whether the Finalize Codex stage can be removed entirely.
  • Define a compatibility and migration policy for existing settings such as finalize-model, finalize-reasoning-effort, and finalize-prompt across CLI flags, environment variables, config files, profiles, help, and config output.
  • Do not silently retain settings that no longer affect runtime behavior.
  • Review, Fix findings, and Fix CI remain Codex-backed stages.

Acceptance criteria

  • An accepted ADR records the deterministic-orchestration ownership rule before implementation begins.
  • A feature package with design and implementation plan covers the public CLI/configuration, agent-contract, workflow-state, event-schema, Git/GitHub connector, timeout, retry, cancellation, and rollout/backout changes.
  • Finalization can commit/checkpoint as allowed by the documented safety policy, push, find/create a PR, and classify CI without starting a Codex finalization session.
  • A linked-worktree test proves publication does not fail because the common Git directory is outside a Codex workspace sandbox.
  • A successful remote push cannot be misreported as unpushed solely because a local remote-tracking update failed.
  • CI polling is pinned to the published head SHA.
  • Default CI timeout is 60 minutes and its configuration precedence is covered by tests and documentation.
  • The first applicable failed check transitions promptly to Fix CI.
  • All-green CI transitions to success only after all applicable checks complete.
  • No applicable CI produces the documented skipped outcome.
  • Deadline expiry produces an explicit timeout outcome and operational exit behavior, without invoking Fix CI.
  • Transient polling errors, permanent provider errors, stale runs, new head revisions, cancellation, and child-process cleanup have deterministic coverage.
  • Existing CI recovery limits and review-after-fix behavior remain intact.
  • Obsolete Finalize model/prompt configuration has an explicit compatibility decision and tested migration behavior.
  • Human and machine-readable progress output clearly expose commit, push, change-request, CI waiting, CI failure, CI timeout, and completion outcomes.
  • Root README and affected Memory Bank canonical owners are updated, and make docs-lint passes.
  • Implementation verification follows the selected feature-package validation profile and memory-bank/engineering/testing-policy.md.

Non-goals

  • Supporting GitLab, Bitbucket, or additional forge/CI providers in this delivery unit.
  • Granting Codex danger-full-access as the permanent solution.
  • Moving reasoning-heavy tests, investigation, or code remediation out of Codex.
  • Redesigning review findings or Fix CI prompts beyond what is necessary to remove deterministic finalization responsibilities.
  • Creating an epic unless discovery proves that this cannot be delivered as one independently verifiable feature.

Delivery routing

This changes CLI behavior, configuration, the Codex agent contract, workflow state/exit behavior, stdout event semantics, Git/CI integration, and architecture. Route it through Feature Flow with Design required: yes; create memory-bank/features/FT-<issue>/. Because the ownership rule is reusable beyond this one implementation, create and accept an ADR within the issue's design phase. Use an Epic only if grounded discovery later demonstrates multiple independent delivery units requiring a shared roadmap and cross-feature risk register.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions