Co-authored-by: nova28 <17953305+nova28@users.noreply.github.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
6.6 KiB
id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
| id | title | status | wave | depends_on | plan | requirements | acceptance_criteria | system_design | |||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-push-path | Explicit push target and expected-branch verification on the push path | completed | 2 |
|
plan.md |
|
|
|
Task 02: Explicit push target and expected-branch verification on the push path
Summary
Wire GitOperator.Push onto Task 01's primitives: evaluate the fixed refusal
list before contacting any remote, skip empty-remote first publication for a
resolved remote other than origin, and verify the expected branch twice, the
second time as the last Git read before the push command. A request that names
neither input performs the same push it performs today.
In scope
- A
resolvePushPlanhelper that evaluates the refusal list in the design's fixed order and yields the resolved remote, the refspec, and the set-upstream decision. - Refusing
push_remote_contribution_conflictandpush_remote_upstream_unsupportedbefore any remote read. - Restricting empty-remote first publication to the
originpath. - Moving
getUpstreamRefahead of the second verification so the branch read is the last Git command before the push. - The second verification, reporting
push_branch_mismatch_after_baselinewithbaseline_publishedset when first publication published a baseline in this request, andpush_branch_mismatchotherwise. - Refspec selection:
HEAD:refs/heads/<expected>with a target and an expected branch,HEAD:refs/heads/<current>with a target alone, unchanged otherwise. - Populating
pushed_remoteandpushed_branchon a successful push only when the request carried an explicit target. - Extending the push completion log with the resolved remote, destination branch, and whether an expected branch was supplied and matched.
Out of scope
PushPreflight, which Task 03 owns even though it reusesresolvePushPlan.- Transport plumbing, which Task 04 owns.
- Contribution routing behavior, its force refusal, and the empty-remote publication mechanics themselves, all of which stay as they are.
- Adding a second output sanitization.
runGitCommandalready redacts everypushinvocation.
Acceptance
- A push naming a configured remote other than
originpublishesHEAD:refs/heads/<branch>to it, sets no upstream, and publishes no baseline. - An expected branch that does not match the current branch, including a
detached
HEAD, refuses the push with the expected and current branches reported and no remote contacted. - A request naming neither input produces the same Git commands and the same
result shape as before this task, with
git_empty_remote_test.gounmodified and green.
Verification
cd apps/backend && go test -tags fts5 ./internal/agentctl/server/process/...
cd apps/backend && make lint
Files likely touched
apps/backend/internal/agentctl/server/process/git.goapps/backend/internal/agentctl/server/process/git_push_target.goapps/backend/internal/agentctl/server/process/git_push_expected_branch_test.go(new)
Dependencies
Task 01.
Risks
Pushis near the backend function-length limit already. KeepresolvePushPlanand the second verification ingit_push_target.gorather than growingPushin place.- The second verification can follow a completed baseline publication, so the
refusal is deliberately not side-effect-free. Do not add a rollback; report
baseline_publishedinstead. - Reordering the upstream read is observable to any test that asserts Git
command sequence on the
originpath. Existing empty-remote tests must pass unmodified; if one fails, the reorder is wrong rather than the test.
Parallelism
parallel-safe
Inputs
- The system design's Control flow and Refusal ordering sections.
Pushatinternal/agentctl/server/process/git.go, andprepareEmptyRemotePublicationingit_empty_remote.go.git_empty_remote_test.goas the regression net for the unchanged path.
Results
Implemented. Push now calls validateContributionState, then
resolvePushPlan, which evaluates the whole refusal list before any remote is
contacted. Empty-remote first publication is gated on plan.baselineEligible,
so it runs only for origin with no contribution routing. resolveSetUpstream
moves the upstream read ahead of the second verification and skips it entirely
on the explicit-target path.
The ordering guarantee is proved rather than asserted: a PATH shim records every
git invocation, and TestGitOperatorPushVerifiesBranchAsLastReadBeforePush
checks that symbolic-ref HEAD immediately precedes push on both the
explicit-target and default paths. A second shim moves HEAD during first
publication so
TestGitOperatorPushReportsMismatchAfterBaselinePublication exercises the
post-baseline refusal, confirming push_branch_mismatch_after_baseline,
baseline_published, and that the task branch stays unpublished while the
baseline remains.
The existing git_empty_remote_test.go cases pass unmodified, which is the
regression evidence that the path naming no target is unchanged.
Verified with go test -tags fts5 ./internal/agentctl/server/process/... and
make -C apps/backend lint.