Repository navigation
feat(agents): issue-161-ci-roadmap-fail-validation-when-a-change - #193
mctl-agents[bot] wants to merge 2 commits into
Conversation
Add a diff-aware lifecycle guard that fails when a completed epic gains required work, wire it into roadmap-validate.yml with full history, and document it in the roadmap README. Proposal: platform-gitops/agents-state/.github/proposals/issue-161-ci-roadmap-fail-validation-when-a-change/ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Claude finished @mctl-agents[bot]'s task in 1m 49s —— View job Review of commit
|
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | ||
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
| run: | | ||
| base="$(git merge-base "$BASE_SHA" "$HEAD_SHA")" |
There was a problem hiding this comment.
P2 — compares against the merge-base, but the checked-out tree is the merge commit.
On pull_request, actions/checkout checks out refs/pull/N/merge, which is base.sha merged with the PR head. So the head manifests (--head-dir roadmap/epics) already include everything that landed on main after the branch point. Using git merge-base "$BASE_SHA" "$HEAD_SHA" as the base blames this PR for those main-side changes.
Concrete false positive: after a branch is cut, an epic is created on main as active and later moved to completed (both legitimate). For any older open PR touching roadmap/**, that epic is missing from the merge-base and completed in the merge tree, so the guard reports BornCompletedUnverified and fails the unrelated PR. The same thing happens for an epic that, on main, was reopened, given a new required item and completed again: the PR gets RequiredItemAdded.
The first parent of the checked-out merge commit is BASE_SHA, so compare against it directly:
run: python3 roadmap/scripts/lifecycle_guard.py --base-ref "$BASE_SHA"HEAD_SHA is then unused. The README sentence "compares the head manifests with the merge base" should be updated too.
| found = guard.check([state(FINOPS)], [state(head, "roadmap/epics/moved.yaml")]) | ||
| self.assertEqual(codes(found), ["RequiredItemAdded"]) | ||
|
|
||
| def test_load_bearing(self): |
There was a problem hiding this comment.
P3 — tautological test. This patches guard.check to return [] and then asserts that the assertion fails, so it passes no matter what the real check does. It does not show that the guard is load-bearing. Either delete it, or turn it into a real control, e.g. a CLI-level test that the mutated corpus exits 1 with the real check and exits 0 when check is stubbed out.
| raise BaseError(f"base-unresolvable: {ref!r} is not a commit here{hint}") | ||
| commit = resolved.stdout.decode().strip() | ||
|
|
||
| listing = _git(repo, "ls-tree", "-rz", "--name-only", commit, "--", subdir) |
There was a problem hiding this comment.
P3 — base and head enumerate manifests differently. The base uses ls-tree -r, which is recursive, while the head uses validate._manifest_paths, which only globs roadmap/epics/*.yaml|*.yml at the top level, and then rebuilds the path as roadmap/epics/<basename> (L176).
If a YAML file is ever added under a subdirectory of roadmap/epics/, the base side will parse it and may exit 2 with base-malformed, while the head side silently ignores it. Path-fallback pairing would also never match it. Not reachable with the current flat layout, but enumerating the same way on both sides would remove the asymmetry. Note that test_requires_recursive_listing currently locks in the recursive behaviour.
There was a problem hiding this comment.
Has P1/P2 findings, changes requested (0 P1, 1 P2, 2 P3): the PR guard compares the merge-commit checkout against the merge-base instead of base.sha, so changes that landed on main after the branch point show up as false RequiredItemAdded/BornCompletedUnverified failures on unrelated PRs.
Antigravity (agy) review — informationalModel: gemini-3.8-flash-high · commit No significant issues found. |
…l-validation-when-a-change Compare against the PR base sha (first parent of the checked-out merge commit) instead of the merge-base, so main-side changes are not blamed on the PR. README wording updated. Finding 2 is the review summary of finding 1 and is resolved by the same change. Proposal: platform-gitops/agents-state/.github/proposals/issue-161-ci-roadmap-fail-validation-when-a-change/ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
@claude review |
|
Claude finished @mctl-agents[bot]'s task in 33s —— View job Review of commit
|
There was a problem hiding this comment.
No P1/P2 findings (2 P3, carried over from the previous review and still open: tautological test_load_bearing; base and head list manifests differently). The P2 merge-base false positive is fixed: the guard now compares against base.sha, which is the merge commit's first parent. Good to merge.
Antigravity (agy) reviewagy did not produce a review on this PR; see the workflow log. Not blocking merge — no verdict was reached, so there is nothing to act on. |
Implements accepted proposal
.github/issue-161-ci-roadmap-fail-validation-when-a-change.Spec: https://github.com/mctlhq/mctl-gitops/tree/main/platform-gitops/agents-state/.github/proposals/issue-161-ci-roadmap-fail-validation-when-a-change/
Generated by mctl-agents Tier 2 implementer. Review carefully — this PR was opened automatically and the spec may have gaps.
Closes #161