feat(missions): publish the mission branch, gated by commit_policy
ci / gates (push) Failing after 13s
ci / rust (push) Skipped
ci / frontend (push) Skipped
ci / e2e (push) Skipped
ci / publish (push) Skipped

Completes delivery. A phase's work is now captured, committed, gated and
pushed — in that order, so every failure costs strictly less than the one
before it.

Publishing is last for a reason. By the time it runs the patch is on disk, the
artifact is registered and the work is on a local branch, so a rejected ref, a
rotated token or an unreachable forge costs a push and nothing else. A test
pushes at a path that does not exist and asserts the commit is still there
afterwards.

The gate decides the branch name, never whether the work survives:

- green, or policy `always`  → `clawmates/mission-<m8>-<p8>`
- red / unrunnable / no suite → `…-wip`
- `on_reviewer_approval`      → `…-review`

Both land on the forge. A human can inspect, fix and re-push a branch; nobody
can recover work discarded for failing a test. Deleting a red branch
reproduces the old behaviour on purpose rather than by accident.

`verify_tests` runs the project's own suite through the runtime container and
returns `Option<bool>` — `None` for "could not establish", which the gate
treats as unproven. An unreadable exit status is not a pass. That is the same
fail-closed stance as the phase evaluator, and it is here because this tranche
has now found four separate things reporting success while doing nothing.

Never force-push. A rejected update is reported and left alone: the remote ref
belongs to whoever set it, and overwriting it to make delivery look tidy is
how a mission eats someone else's commit.

The push URL is built fresh from the repo row and the ambient token, not read
from `.git/config` — which no longer carries credentials, since agents run as
root in a container that mounts the checkout.

Tests push to a real `git init --bare` remote and assert the ref and its
content actually arrived. A mock would have accepted anything.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-02 13:15:38 -07:00
co-authored by Claude Opus 5
parent 3ea288dbb5
commit e2871c4361
3 changed files with 317 additions and 2 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ pub async fn ensure_checkout(
/// environment, rewrite it to include the token as basic-auth. Returns
/// the URL unchanged otherwise. The token is never logged (we only
/// pass the rewritten URL into `git clone` via argv).
fn with_ambient_auth(url: &str) -> String {
pub(crate) fn with_ambient_auth(url: &str) -> String {
let Ok(token) = std::env::var("GITEA_TOKEN") else {
return url.to_string();
};