Repository navigation
chore(shepherd): enable SHEPHERD_FIX_ONLY_SERVICES so the #292 path takes effect - #1202
Conversation
…akes effect mctl-agents#292 split shepherd ownership by stage: fix-only means the shepherd discovers, reviews and pushes follow-up commits, while decide() returns defer-merge so the merge decision stays with the other PR lifecycle. That is what gives a steward-owned repository a path from a blocking review finding back to code -- the pr-steward can say what is wrong but has nothing that fixes it. The code shipped in mctl-agents#341 on 2026-09-11 and has been dark since, because this value was never set. Every steward-owned repo stayed in SHEPHERD_SKIP_SERVICES, so the review-feedback path #292 added was unreachable in production and deployed behaviour was still the binary FULL/SKIP it had been before. #1073 is the standing evidence: blocking findings from claude[bot] and agy since 2026-09-09, and no actor able to address them. Values are the ones the approved #292 proposal specifies, task 9 of agents-state/mctl-agents/proposals/issue-292-fix-lifecycle-steward-owned-repos-have-n/tasks.md. Deviation from that task, stated rather than made silently: it says to set the values "in both cronworkflow-mctl-agents-shepherd.yaml and cwft-mctl-agents-shepherd.yaml". The CronWorkflow has no env block at all -- it is a parameters-only wrapper (service, slug, dry_run) around the CWFT, so there is no second place to set this. The CWFT is the only one, and it is also the one the proposal's own rationale names as load-bearing, since it is what DevLoopWorkflow._shepherd_tick inherits. Setting it once covers both entry points. mctl-academy stays in SKIP and is why the two lists are not redundant: it is skipped by the shepherd and absent from the steward's repo list, so nothing auto-merges it at all. Its clean-room content policy makes human CODEOWNER approval the last check before a question publishes. Reversible by reverting this commit; fix-only wins over skip, so the two list edits are order-independent. Refs: mctlhq/mctl-agents#292, #1073, mctlhq/.github#57 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsqpZXEnvZR8aTpZ6vXRaz
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Claude encountered an error after 0s —— View job I'll analyze this and get back to you. |
|
Claude finished @mashkovd's task in 1m 15s —— View job Review complete ✅
Findings: None (P1/P2/P3). This is a values-only change to Verified independently:
Approving as a trivial config/values change per review policy.
|
Antigravity (agy) review — informationalModel: gemini-3.1-pro-high · commit Severity: P1 Severity: P3 |
Response to the agy P1 — verified link by link, and the hardening is shippingP1 — "an AI agent can author, push and effectively merge configuration changes directly into the cluster without any human CODEOWNER gate." Checked rather than assumed. The chain does not close today, and the middle link is factually wrong for this repository:
So the P1 is not confirmed as a live defect, and this PR does not create the pipeline it describes. The proposed alternative fix is right, though, and it is shipping. All three of those guards are configuration — two of them in another repository — and one edit reopens the path.
That PR lands before this one, so the code-level guarantee exists before the env var widens the shepherd's reach. P3 — no test coverage for the new lists. The behaviour these values select is tested in What is genuinely missing is a check on the invariant between the two repositories — that the shepherd's lists and the steward's repo list stay a total, disjoint partition. Today that invariant is asserted only in a comment in |
Correction to this PR's verification sectionMerged, and the rollout is live. But the verification step I wrote — "watch #1073 is proposal-less. Its head branch is So #1073 needs both halves: this change (so the shepherd touches What this change actually does, checked against current stateThe shepherd now discovers proposals in
So there is exactly one PR this reaches today, and the honest prediction for it is That is a fair demonstration of why Nothing here is unsafe — Tracking the accurate verification target on |
The gap
mctlhq/mctl-agents#292split shepherd ownership by stage rather than by repo:decide()returnsdefer-mergeinstead ofmerge, so the merge decision stays with the other PR lifecycle (pr-steward).That is what gives a steward-owned repository a path from a blocking review finding back to code. Before it, the pr-steward could say what was wrong and had nothing that could fix it.
The code shipped in
mctlhq/mctl-agents#341on 2026-09-11 and has been dark ever since, because this value was never set.SHEPHERD_FIX_ONLY_SERVICESis read byrun_shepherd.py, documented in its module docstring, inREADME.mdand in ADR-006's #292 addendum — and set nowhere in this repo. Every steward-owned repo stayed inSHEPHERD_SKIP_SERVICES, so deployed behaviour was still the binary FULL/SKIP it had been before #292, and the review-feedback path was unreachable in production.mctlhq/mctl-gitops#1073is the standing evidence: blocking findings fromclaude[bot]and agy since 2026-09-09, and no actor able to address them.Found while reconstructing the ownership graph for
mctlhq/.github#57, where this is pilot path 3.The change
These are the values the approved #292 proposal specifies — task 9 of
agents-state/mctl-agents/proposals/issue-292-fix-lifecycle-steward-owned-repos-have-n/tasks.md.One deviation from that task, stated rather than made silently
The task says to set the values "in both
cronworkflow-mctl-agents-shepherd.yamlandcwft-mctl-agents-shepherd.yaml".The CronWorkflow has no env block at all — it is a parameters-only wrapper (
service,slug,dry_run) around the CWFT, so there is no second place to set this:The CWFT is the only location, and it is also the one the proposal's own rationale names as load-bearing — "the CWFT env is what
DevLoopWorkflow._shepherd_tickinherits". Setting it once covers both the cron entry point and the in-loop tick.Why
mctl-academystays in SKIPIt is the reason the two lists are not redundant: academy is skipped by the shepherd and absent from the steward's repo list, so nothing auto-merges it at all. Its clean-room content policy makes human CODEOWNER approval the last check before a question publishes. It is additionally hardened in code —
NEVER_MERGE_SERVICEScaps it at fix-only in_service_mode, so no value here can ever resolve it tofull.Blast radius and reversal
Four repos move from "shepherd discovers nothing" to "shepherd discovers and may push a follow-up commit". Merge authority does not move:
decide()returnsdefer-mergefor every one of them, and the pr-steward's ownmerge_modeis unchanged (neverfor mctl-gitops,when-greenfor the others).Reversible by reverting this commit. Fix-only wins over skip, so the two list edits are order-independent and there is no half-applied state.
Verification after merge
Wait ~3 min for ArgoCD to sync (Argo snapshots templates at submit time), then watch
mctlhq/mctl-gitops#1073get a shepherd tick and a follow-up commit, with the merge still deferred.Refs
mctlhq/mctl-agents#292,mctlhq/mctl-gitops#1073,mctlhq/.github#57🤖 Generated with Claude Code
https://claude.ai/code/session_01FsqpZXEnvZR8aTpZ6vXRaz