feat(source-control): dedicated --self/--extra-self self-identity flags for babysit snapshot#882
Conversation
…gs for babysit snapshot The babysit snapshot derived `self_logins` (the posting identities whose comments self-classification suppresses) from the `--author` discovery filter, conflating two distinct concerns. That broke in both directions (#511): configured extra self identities were dropped whenever autopilot widening drops `--author` (a bot poster's own comments re-fired `new_human_blocking_feedback` every cycle), and a discovery `--author` for a different login was wrongly treated as self (suppressing that author's genuine feedback from the worker-dispatch arm). `pr_queue_snapshot.py` now resolves self-identity from dedicated `--self` (full override) / `--extra-self` (added to `@me`) flags, mirroring `babysit-readiness-gate.sh`'s flag semantics, independent of `--author` and for both `--queue` and `--pr` scope. This supersedes the `@me`-only union from #494 and removes the author-derived self fallback in `build_config` (and the now-dead `resolved_authors` carrier), so no discovery author can leak into the self set. Red-green regression tests assert both directions at the `build_snapshot` level. The `resolve_self_logins` unit tests that pinned the old author-union contract are rewritten to the new flag-based contract. Structural parity with the gate, not exact on one edge: an unresolvable `@me` raises (fail-loud) rather than degrading to the extras; that parity decision is tracked in #881. Per-plugin bump 0.15.9 -> 0.16.0 (minor: new CLI surface) + CHANGELOG. Closes #511 Refs #881 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 54s —— View job PR Review — feat(source-control): dedicated --self/--extra-self self-identity flags for babysit snapshot
SummaryThis is a clean, well-scoped fix for #511. The conceptual separation of discovery authors from self-identity is correct and the implementation follows through cleanly. The regression test structure — asserting both the under-inclusion and over-inclusion directions at the Observations1.
self_login = gh.resolve_author("@me")
if self_login:
source.append(self_login)The docstring (L113–114) says:
But the The test 2.
if self_csv:
source = _csv_list(self_csv)
else:
source = _csv_list(extra_self_csv)
...When both 3. Minor duplication between def _csv(value: str | None) -> frozenset[str]:
return frozenset(
part.strip() for part in (value or "").split(",") if part.strip()
)
def _csv_list(value: str | None) -> list[str]:
return [part.strip() for part in (value or "").split(",") if part.strip()]Near-identical bodies with only the container type differing. 4. SKILL.md step 4 — unquoted The value could contain commas ( What's correct
|
|
Claude finished @kyle-sexton's task in 3m 10s —— View job Security Review — PR #882
SummaryNo CRITICAL or IMPORTANT vulnerabilities found in this diff. The core change — decoupling SUGGESTION —
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20f974366a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
claude-ops: #844 rebased and re-derived its claim from 0.17.2 to 0.17.4, colliding exactly with this branch's prior 0.17.4. Bump to 0.17.5. source-control: a new PR, #882 (fix/511-babysit-self-identity-decouple), claims 0.16.0 — a minor bump above this branch's prior 0.15.11 and above #840's 0.15.10. Bump to 0.16.1 to stay ahead of both. repo-hygiene (0.4.6), guardrails (0.9.6), and work-items (0.19.1) were re-verified fresh against current main and every live open PR (main: repo-hygiene 0.4.5, guardrails 0.9.5, work-items 0.19.0; #861 0.19.0) and remain correct, no change needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
#844 (claude-ops) merged into main at exactly 0.17.4, which this branch's prior 0.17.5 was already one past — kept as-is, no re-bump needed for the number itself, just resolved the resulting plugin.json/CHANGELOG.md conflict. Full fresh collision sweep after the merge found claude-ops now has NO open-PR collision at all. It also found #861 (work-items) re-derived its own claim from 0.19.0 to 0.20.0 since the last check (following #857's Jira-adapter minor bump into main) — colliding with this branch's prior 0.19.1. Re-bumped work-items to 0.20.1. source-control (0.16.1, held behind #882's 0.16.0 and #840's 0.15.10), repo-hygiene (0.4.6, no collision), and guardrails (0.9.6, no collision) re-verified against current main and all live open PRs — unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
`resolve_self_logins` tested `self_csv` for truthiness, so an explicit
`--self ""` (flag supplied, empty value) fell through to the "flag
omitted" branch and resolved/added `@me` -- silently contradicting the
documented full-override contract ("`@me` is NOT added"). Switch the
guard to `is not None` so only an actually-omitted flag falls through.
Also document that `--self` takes precedence over `--extra-self` when
both are supplied, and drop `plugin.json`'s stale `babysit_self_logins`
description clause: self-identity no longer feeds discovery scope after
the `--author`/self decoupling in this branch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 1s —— View job
Review — follow-up commit
|
|
Claude finished @kyle-sexton's task in 1m 48s —— View job Security Review — PR #882
SummaryNo CRITICAL or IMPORTANT vulnerabilities found. The two SUGGESTION-level findings from the prior security review on commit Prior findings: both resolvedSUGGESTION 1 — Commit SUGGESTION 2 — stale "discovery scope" in Resolved: the Residual observation
self_login = gh.resolve_author("@me")
if self_login:
source.append(self_login)The docstring states Notes on non-findings
|
(The "No CRITICAL or IMPORTANT vulnerabilities found" line earlier in this comment is prose, not a live finding — not tabulated.) |
|
…discovery filter (#897) Author ruling on the #897 discovery-contract fork (Codex flagged on #882): filter and stopped joining babysit_self_logins onto --author, but the userConfig `description` still listed "discovery scope" first — code and documented contract disagreed. and "a distinct concern from --author (which authors' PRs to discover)," and its fix direction explicitly drops the `--author @me,<self-logins>` extension. So the pre-#511 discovery-widening was an incidental side effect of the old author-derived self set, not a stated goal. Ruling: keep the discovery-drop (option B); babysit_self_logins is a suppression/classification/merge-exemption set only — which authors' PRs the queue discovers stays --author's job. Correct the userConfig description to match; no code change (the code already behaves this way post-#511). Part of the unreleased 0.16.0 (#511) entry. Refs #511 #897 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 23s —— View job PR Review — commit
|
|
Claude finished @kyle-sexton's task in 2m 16s —— View job Security Review — PR #882
SummaryNo CRITICAL or IMPORTANT vulnerabilities found. This review covers the full three-commit diff, including the latest docs-only commit Prior SUGGESTION findings: both resolvedSUGGESTION 1 —
SUGGESTION 2 — stale "discovery scope" language in Fully resolved across two commits: Residual note (informational, pre-existing, not a security finding)
self_login = gh.resolve_author("@me")
if self_login:
source.append(self_login)The docstring (L113–114) and Notes on non-findings
|
#882 (source-control) merged into main at 0.16.0, which this branch's prior 0.16.1 was already one past — resolved the resulting plugin.json/CHANGELOG.md conflict, kept as-is. Full fresh collision sweep after the merge found source-control now carries TWO additional open PRs beyond #840: #895 (fix/548-babysit-worktree-head-safety, claims 0.15.10) and #898 (feat/399-shared-worktree-helper, claims 0.17.0 — a minor bump above this branch's prior 0.16.1). Re-bumped source-control to 0.17.1 to stay ahead of all three (#898's 0.17.0, #895's and #840's 0.15.10). claude-ops (0.17.5, no collision), work-items (0.20.1, held behind #861's 0.20.0), repo-hygiene (0.4.6, no collision), and guardrails (0.9.6, no collision) re-verified against current main and all live open PRs — unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
Integrate the latest main (source-control advanced to 0.16.0 via #511's pr_queue_snapshot self-identity work, plus #882). Re-derived this PR's bump to 0.16.1 (one past current main) and re-labeled the CHANGELOG entry from 0.15.10 to 0.16.1, stacked above the merged-in 0.16.0 entry. safety.md, orchestration.md, review-discipline.md, and SKILL.md auto-merged (my bin/-path edits and the upstream changes touch distinct regions); babysit-prs skill-quality gate green at 499/500 lines.
…utate; merge-only, upstream refspec push (#895) ## Summary Fixes #548. A babysit PR worker can be assigned a git worktree in **detached HEAD** — because the PR branch is already checked out in a sibling/foreign worktree — or on a **stale local branch tip** behind the PR head. The checkout/freshness mechanics then merged and pushed from that tip, so a stale-tip integration could **silently revert the newest branch commit** — a near-miss where safety depended on the assigned `HEAD` happening to match, not on a guard. The initial reviewer pass confirmed the safety.md contract text was sound but raised a **CRITICAL**: the actual worker mechanics (loop.md/SKILL.md/orchestration.md) were unreconciled, so an agent following the literal steps still hit the failure. This PR fixes the contract **and** the mechanics that implement it. ## The fix - **`reference/safety.md` Checkout And Push Invariants** — assert the assigned worktree's `HEAD` equals the **true PR head** (`gh pr view <N> --json headRefOid`; equal to `origin/<headRefName>` for a same-repo PR) before any merge/edit/push; **stop** on a stale/detached mismatch. Push by explicit refspec to the branch's configured upstream `git push "$(git config --get branch.<headRefName>.remote)" HEAD:<headRefName>` (fast-forward by construction, never `--force`/`--force-with-lease`). The reuse rule is reconciled so it permits the detached-HEAD path under the same assertion (no self-contradiction). - **`reference/loop.md` §5.1.2** — acquire the head via `gh pr checkout` (heals a behind-origin local branch; `--detach` for a sibling-locked branch; resolves fork PRs), assert `HEAD == PR_HEAD` (the live `headRefOid`) in every checkout path, degrade to read-only on mismatch. `SKILL.md` Step 0.2 + the cross-tier invariants and `reference/orchestration.md`'s conflict-worker follow the same assertion + refspec push. `worktrees.md` gets a one-line pointer (not a duplicate). - **Freshness is now merge-only.** The prior loop.md path rebased-and-`--force-with-lease`d linear-history branches — which both violated the skill's own never-force-push invariant (`safety.md` "Never Do Automatically", `orchestration.md`) and was the silent-revert vector. Behind-default branches now always integrate via `git merge` + a fast-forward refspec push. **Behavior change:** linear-history branches now carry an interim merge commit during freshness instead of being rebased (the final squash merge still flattens history). ## Scope decisions (called out for review) - **Fork/cross-repo heads (Option B — upstream-aware push).** The push targets the branch's *configured upstream* — `git push "$(git config --get branch.<headRefName>.remote)" HEAD:<headRefName>` — which resolves to `origin` for a same-repo head and to the fork's remote for a **write-allowed in-owner fork** head (a real supported case: `branch_write_allowed=true` for cross-repo heads under `<watched-owners>`). An earlier revision hardcoded `origin`, which the re-review flagged as a regression that would silently write a same-named branch on the base repo for a fork PR; this fixes it while keeping the origin refspec for same-repo heads. An external-fork head *outside* watched owners remains safety.md's read-only stop-and-ask case. The assertion uses the live `headRefOid`, correct for any PR type. - **Enforcement stays agent discipline.** Whether the head assertion belongs in a deterministic push-safety guard (rather than prose the worker follows) is filed as follow-up **#885**. ## Verification (local gates) - `check-skill-portability.sh origin/main` — PASS (5 skill files). - `check-changelog-parity.sh --check-bump origin/main` — PASS (0.15.10 entry present). - `markdownlint-cli2` on the changed docs — clean; SKILL.md 499/500 lines; `evals.json` (id 6 updated to the merge-only + upstream-refspec contract) valid; `plugin.json` valid. - Python unittest suite unaffected (no code changed) — 339 tests OK. - Two independent fresh-context review rounds: round 1 raised a CRITICAL (the mechanics docs were unreconciled with the safety.md contract) — fixed by reconciling loop.md/SKILL.md/orchestration.md; round 2 raised a CRITICAL (hardcoded-origin push broke in-owner forks) — fixed by Option B (upstream-aware push). ## Version Per-plugin bump **0.15.9 → 0.15.10** (patch). `marketplace.json` pins no version for `source-control`, so only `plugin.json` changes. > **Ordering note for the merge lane:** my open PR #882 (#511) bumps `source-control` to **0.16.0** and is unmerged. If #882 merges first, re-bump this **above 0.16.0 (→ 0.16.1)** during recompose — do not keep 0.15.10. Closes #548 ## Related - #885 — follow-up (filed): promote the head assertion from prose to a deterministic push-safety guard. - #524 — worker-lease cross-session exclusivity (distinct: *which session* may work a PR; this is the *git mechanics* of the assigned worktree). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Fixes #511. The babysit PR-queue snapshot derived
self_logins— the posting identities whose comments self-classification suppresses — from the--authordiscovery filter, conflating two distinct concerns (which authors' PRs to discover vs whose comments to suppress). That broke in both directions:babysit_self_logins) rode on--author, so when autopilot widening drops--authorentirely, a bot poster's own comments re-firednew_human_blocking_feedbackevery cycle.--queue --author alicerun authenticated as a different login madealicea self-login, suppressing Alice's genuine feedback from the worker-dispatch arm.The fix
pr_queue_snapshot.pynow resolves self-identity from dedicated--self(full override — exactly the given logins,@menot added) /--extra-self(added on top of the authenticated@me) flags, mirroring the existingbabysit-readiness-gate.shsemantics, resolved independently of--authorand before the--pr/--queuescope split (so single-PR scope is covered too). This supersedes the@me-only union added in #494, and the author-derived self fallback inbuild_configis removed so no discovery author can leak into the self set in any path.The skill's step-4 invocation and the
babysit_self_loginsuserConfig table row now route the configured extras through--extra-selfinstead of overloading--author @me,<self-logins>; because self-identity no longer rides on--author, it survives autopilot widening.Tests (red-green, with transparency on the rewritten spec)
SelfIdentityDecouplingTestsasserting both directions at thebuild_snapshotlevel (extra-self survives a dropped--author; a discovery author is not treated as self). Verified these fail against the pre-fix author-union code and pass after the fix.resolve_self_loginsunit tests pinned the old author-union contract; they are rewritten to the new flag-based contract, andtest_discovery_authors_are_unioned_with_the_self_login(which asserted the over-inclusion behavior now fixed) is deleted.test_raw_author_fallback_drops_me_when_unresolvedbecomestest_missing_resolved_self_logins_yields_empty_not_author. These are a ratified spec change (the issue's converged decision), not test weakening.Verification (local gates)
python -m unittest discover -s tests -p 'test_*.py'(the CI entry viaengine.test.sh) — 341 tests OK.check-changelog-parity.sh --check-bump origin/main— PASS (0.16.0 entry present).check-skill-portability.sh origin/main— PASS.check-changed-skills.sh— SKILL.md 499/500 lines (under the hard cap); the one reported "engine.test.sh failed" is the pre-existing repo-wide ruff E402 quirk that does not reproduce in CI (main is green; merged babysit PRs chore: declare shell: bash on every skill with dynamic-context injections #860/fix(source-control): actionable owner/repo diagnostic on readiness-gate fetch failure #839 pass skill-quality-gate), and this change adds zero new ruff errors (32 before == 32 after).markdownlint-cli2on the changed docs — clean;plugin.jsonvalid.Version
Per-plugin bump 0.15.9 → 0.16.0 (minor — new
--self/--extra-selfCLI surface alongside the behavior fix).marketplace.jsonpins no version forsource-control, so onlyplugin.jsonchanges.Closes #511
Related
--prsnapshot mode leavesself_loginsempty (self-filter + foreign-activity dormant) #497 — single---prscope leavesself_loginsempty (sibling facet of the same seam, triaged blocked-by babysit-prs: decouple self-identity from --author so configured self-login extras survive autopilot widening #511). This change resolves self-identity for--prscope too, but its acceptance is left for the babysit-prs: single---prsnapshot mode leavesself_loginsempty (self-filter + foreign-activity dormant) #497 lane to verify — not closed here.@me-only--queueunion this supersedes.@mewhere the readiness gate degrades to the--extra-selfset; tracks whether fail-loud is the intended contract. Surfaced in this PR's review.🤖 Generated with Claude Code