Git Completion Contract (Mandatory)¶
Standard ID: ES-GITCC Date: 2026-07-19 Updated: 2026-09-10 Authority: Engineering Standard — Bluefly Agent Platform Scope: All agent-executed tasks that produce code, configuration, or documentation changes in a Git repository. Docs agents are in scope. Chat reports are not completion.
This contract is the hard completion law. It supersedes any weaker reading that treated a local commit, a green test run, a pushed branch, or an open MR as done.
Related: AGENTS.md, git-discipline.md, git-standard.md, factory-operating-contract.md, blucity-operator-contract.md, beads-work-ownership-contract.md.
Axiom¶
Work on disk is not done. A commit is not done. A pushed branch is not done. An open MR is not done. A green MR is not done.
An agent is not finished because code exists in a worktree.
An agent is not finished because tests pass.
An agent is not finished because it reported a result in chat.
An agent is not finished because it pushed a branch.
An agent is finished only when valid completed work is durable in GitLab and integrated into release/v0.1.x, unless an explicit external blocker prevents that.
DONE (feature / fix / chore)
=
implemented
+ tested
+ committed
+ pushed
+ MR to release/v0.N.x
+ CI passed
+ merged into release/v0.N.x
+ merge verified
+ development package published (when the project produces an artifact)
+ verified
+ worktree removed
+ bead reconciled
Feature work does not wait for release/v0.N.x → main. That is a separate promotion lifecycle.
FEATURE_BEAD_CLOSES_AFTER_RELEASE_INTEGRATION=YES
FEATURE_BEAD_WAITS_FOR_MAIN=NO
THOMAS_FEATURE_MERGE_REQUIRED=NO
FEATURE_TO_RELEASE_AUTOMATIC=YES
RELEASE_TO_MAIN_AUTO_MERGE=NO
RELEASE_TO_MAIN_HUMAN_GATE=YES
Never knowingly leave finished valid work uncommitted.
That last rule exists because the estate already contains this defect class: a “polecat-done handoff push-step gap” where Refinery was handed unpushed branches, plus WIP that was uncommitted and had no authorizing bead.
HARD LAW: NEVER LEAVE VALID WORK UNCOMMITTED¶
VALID_COMPLETED_WORK + UNCOMMITTED = FAILURE
VALID_COMPLETED_WORK + UNPUSHED = FAILURE
VALID_COMPLETED_WORK + NO_MR = FAILURE
GREEN_MERGEABLE_MR + NOT_MERGED = FAILURE
MERGED_MR + ABANDONED_WORKTREE = CLEANUP_FAILURE
Do not end a session with valid completed work sitting only on disk.
If you modified tracked source and the change is valid:
YOU MUST COMMIT IT.
If you committed valid work:
YOU MUST PUSH IT.
If you pushed a feature branch:
YOU MUST OPEN OR UPDATE AN MR TO release/v0.1.x.
If the MR is green, approved as required, conflict-free, and acceptance criteria pass:
YOU MUST MERGE IT TO release/v0.1.x.
Do not merely report that it is “ready to merge.”
Do not ask Thomas:
Should I merge this feature into release?
If acceptance criteria are satisfied and policy permits merge: merge it. Thomas is not the feature merge-queue operator. Thomas owns only whether release/v0.N.x is ready to promote to main.
If policy or permissions prevent the agent from performing the merge, report that as an explicit blocker:
BLOCKED_BY=MERGE_PERMISSION_OR_OPERATOR_GATE
and do not claim completion.
A weekly limit, context limit, provider interruption, handoff, or session restart does not turn local filesystem state into completion.
Before loss of session capacity, preserve work:
commit → push → update MR → update bead/handoff
at minimum.
Required lifecycle¶
claim bead
→ create/use feature branch + isolated worktree
(CANONICAL_ENGINEERING_WORKTREE_ROOT=[WORKSPACE-ROOT]/worktrees/<task>;
FORBIDDEN=[WORKSPACE-ROOT]/BluCity/.gc/worktrees)
→ implement
→ test
→ commit
→ push
→ open MR to release/v0.1.x
→ fix CI / review findings
→ merge to release/v0.1.x
→ shared CI publishes the next development package (artifact projects)
→ verify branch is contained in release
→ remove completed worktree
→ remove merged local branch
→ close/update the **feature** bead with evidence
Do not close a development bead merely because implementation is complete locally. Close or finalize a feature bead only after:
DONE=YES requires:
MR_MERGED=YES
DEPLOYED=YES
RUNTIME_VERIFIED=YES
BEAD_CLOSED=YES
WORKTREE_DEREGISTERED=YES
WORKTREE_REMOVED=YES
RECEIPT MUST INCLUDE:
WORKTREE_PATH=
WORKTREE_REMOVED=YES
Do not keep the feature bead open waiting for promotion to main. Maintain one promotion bead per project/release line for the release/v0.N.x → main MR, target patch, readiness, and promotion verification. Feature beads may link to it; they are not blocked by it after they land in release.
Record the MR/commit/verification receipt in the Bead before final closure where the workflow supports it. If an MR cannot be merged because of an external gate, keep the Bead open/blocked with the exact blocker.
Branch law¶
Normal engineering work flows:
feature/fix/chore branch
→ release/v0.1.x
→ main only through the separate governed promotion process
Never:
feature → main
main → release/v0.1.x
Do not modify the separate release→main promotion workflow during a convergence sweep. Those MRs targeting main from release/v0.N.x are not feature work and must not be retargeted or auto-merged as if they were.
There must be exactly one active promotion MR per project for the active release branch. If none exists after the first release-branch change, create it. If one exists, update it — do not open a duplicate.
Automation may create/update the promotion MR, run CI, calculate the stable patch, generate notes, and mark ready. It must not merge it unless Thomas explicitly authorizes that promotion.
PROMOTION_MR_AUTO_CREATE=YES
PROMOTION_MR_AUTO_UPDATE=YES
PROMOTION_MR_DUPLICATES=0
AUTO_MERGE_RELEASE_TO_MAIN=NO
Versioning (patch-only automation, development sequence, shared gitlab_components owner) lives in git-standard.md.
Remotes use git@gitlab-bluefly:blueflyio/... — never [email protected]:.
Sweep every Rig¶
For every registered Rig, inspect:
- Dirty worktrees.
- Untracked files that appear to be implementation work.
- Local branches.
- Local-only commits.
- Remote feature branches.
- Pushed branches with no MR.
- Open MRs.
- MRs targeting the wrong branch.
- Failed pipelines.
- Mergeable green MRs that agents abandoned before merge.
- Branches already merged into
release/v0.1.x. - Worktrees belonging to already-merged branches.
- Beads marked complete whose Git lifecycle was never completed.
- Beads still open even though their corresponding MR is merged.
Do not assume age means disposable. Do not delete unexplained work.
Classification¶
Every discovered or in-flight work unit must be assigned exactly one state:
UNCOMMITTED
UNPUSHED
PUSHED_NO_MR
MR_OPEN
MR_WRONG_TARGET
MR_BLOCKED
MR_CI_FAILED
READY_TO_MERGE
MERGED_CLEANUP_PENDING
COMPLETE
ABANDONED_REQUIRES_REVIEW
Record:
RIG=
BEAD=
WORKTREE=
BRANCH=
DIRTY_FILES=
LOCAL_ONLY_COMMITS=
REMOTE_BRANCH=
MR=
MR_TARGET=
CI=
STATE=
BLOCKER=
NEXT_ACTION=
Do not assume age means disposable. Do not delete unexplained work. Unclear ownership is ABANDONED_REQUIRES_REVIEW, not a clean-tree license.
Execute — do not stop at inventory¶
UNCOMMITTED¶
Inspect the diff and determine whether it belongs to an authorized work unit.
If valid: run required tests → commit → push → open/update MR.
Never discard valid work just to obtain a clean tree.
UNPUSHED¶
Verify the commits, then push the branch and open/update an MR to release/v0.1.x.
PUSHED_NO_MR¶
Inspect branch intent and diff. If valid, open MR with TARGET=release/v0.1.x.
MR_WRONG_TARGET¶
If ordinary feature work incorrectly targets main, retarget it to release/v0.1.x provided doing so preserves the intended history and policy. Do not retarget a governed release/v0.1.x → main promotion MR.
MR_CI_FAILED¶
Investigate and fix the root cause. If the failure belongs to shared CI, fix blueflyio/gitlab_components. Do not introduce one-off consumer CI to bypass the shared component. Push the fix, rerun the pipeline, continue until PASS or genuinely blocked.
READY_TO_MERGE¶
When all of these hold:
CI=PASS
CONFLICTS=NO
TARGET=release/v0.1.x
ACCEPTANCE=PASS
REQUIRED_REVIEW=PASS
then merge the MR. The expected terminal state is MR_MERGED=YES, not MR_READY=YES. Do not ask Thomas whether to merge ordinary feature work into release/v0.N.x. Do not auto-merge a release/v0.N.x → main promotion MR.
MERGED_CLEANUP_PENDING¶
First prove containment:
git fetch origin
git merge-base --is-ancestor <branch-sha> origin/release/v0.1.x
Only after success: remove the worktree, remove the merged local branch, prune stale worktree metadata.
Use trash for filesystem deletion. Never shell rm. Never use git clean, git reset --hard, or git stash to hide unresolved work.
Session exit gate¶
Before any coding or docs agent stops, hands off, sleeps, or declares completion, it MUST run:
git status
git branch
git log for local-only commits
remote branch existence
MR existence/status
CI status
merge status
worktree cleanup status
bead status
The agent may exit normally only when:
UNCOMMITTED_VALID_WORK=0
UNPUSHED_COMMITS=0
PUSHED_BRANCH_WITHOUT_MR=0
GREEN_MERGEABLE_MR_LEFT_UNMERGED=0
MERGED_WORKTREE_LEFT_BEHIND=0
Otherwise continue executing.
Fleet sweep¶
When draining an estate, do not stop because one Rig is blocked.
record blocker → route blocker → continue to next work unit
The purpose is to drain existing valid engineering work into canonical GitLab state. Do not create unrelated feature work during a sweep.
Do not use:
rm
git clean
git reset --hard
git stash
to hide unresolved work.
Failure contract¶
If commit, push, MR creation, CI, or merge fails for a reason the agent cannot clear:
- STOP that unit.
- Report the exact error.
- Set
BLOCKER=to the named external authority or gate. - Do not claim completion.
- Continue to the next independent work unit when sweeping a fleet.
STATUS: BLOCKED
BLOCKED_BY: <named gate>
Reason: <exact error>
Required operator action: <exact action>
The agent may never leave work in this state and report complete:
- valid completed work uncommitted
- committed locally and not pushed
- pushed with no MR to
release/v0.1.x - green mergeable MR left unmerged (unless
BLOCKED_BY=MERGE_PERMISSION_OR_OPERATOR_GATE) - merged MR with an abandoned worktree
Final report (required)¶
Every completed task ends with:
Repository:
Branch:
Commit:
Remote:
Push: SUCCESS / FAILED
MR: URL
MR_TARGET: release/v0.1.x
CI: PASS / FAILED / BLOCKED
MR_MERGED: YES / NO
MERGE_VERIFIED: YES / NO
DEV_PACKAGE: YES / N/A / BLOCKED
WORKTREE_CLEANED: YES / NO / N/A
BEAD:
FEATURE_BEAD_WAITING_FOR_MAIN: NO
STATUS: COMPLETE / BLOCKED
A fleet sweep additionally returns:
RIGS_AUDITED=<n>
DIRTY_WORKTREES_FOUND=<n>
UNCOMMITTED_FOUND=<n>
UNCOMMITTED_COMMITTED=<n>
UNPUSHED_FOUND=<n>
UNPUSHED_PUSHED=<n>
PUSHED_NO_MR_FOUND=<n>
MRS_CREATED=<n>
WRONG_TARGET_MRS_FOUND=<n>
WRONG_TARGET_MRS_FIXED=<n>
FAILED_MRS_FOUND=<n>
FAILED_MRS_FIXED=<n>
READY_TO_MERGE_FOUND=<n>
MRS_MERGED_TO_RELEASE=<n>
MERGED_WORKTREES_FOUND=<n>
WORKTREES_REMOVED=<n>
MERGED_BRANCHES_FOUND=<n>
LOCAL_BRANCHES_REMOVED=<n>
BEADS_RECONCILED=<n>
BLOCKED_ITEMS=<n>
UNKNOWN_OR_UNSAFE_ITEMS=<n>
VALID_WORK_LEFT_UNCOMMITTED=0
VALID_COMMITS_LEFT_UNPUSHED=0
VALID_PUSHED_BRANCHES_WITHOUT_MR=0
GREEN_MERGEABLE_MRS_LEFT_UNMERGED=0
MERGED_WORKTREES_LEFT_BEHIND=0
FEATURE_TO_MAIN_MRS=0
MAIN_MERGED_INTO_RELEASE=NO
VALID_WORK_DISCARDED=0
RM_USED=NO
For anything remaining:
RIG | BEAD | BRANCH | WORKTREE | MR | STATE | BLOCKER | NEXT_ACTION
Exceptions¶
The operator may explicitly instruct an agent not to push or merge (local-only draft, staging for review). Document the exception and the reason. Absent that instruction, commit-only, push-only, and open-MR-only are incomplete.
Release→main promotion remains a separate governed workflow. This contract does not authorize merging release/v0.N.x to main. Versioning and the shared CI owner are git-standard.md.
artifact:
owner: BluCity-Docs
consumer: All agents performing Git operations, including docs agents
purpose: Prevents agents from claiming completion on uncommitted, unpushed, un-MRed, or unmerged valid work
lifetime: permanent
authority: BluCity-Docs
replaces: weaker ES-GITCC reading that treated remote push as completion
enforcement: agent-directive + operator sweep