Skip to content

Bound handoff.py's Writes Whatever the Label State - #2266

Merged
ptr727 merged 2 commits into
developfrom
feature/handoff-write-boundary
Oct 1, 2026
Merged

ptr727 merged 2 commits into
developfrom
feature/handoff-write-boundary

Conversation

@ptr727

@ptr727 ptr727 commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Copilot's review of promotion PR #2254 (High) found that handoff.py checked the owner and fork status only when the handoff label was missing. That came in with #2265. So new or link against another owner's repository still wrote there whenever that repository happened to carry a handoff label. An unregistered non-fork under the owner slipped past the registry-drift refusal the same way. These writes run as gh subprocesses, which the calling agent's write guard never sees, so the script has to enforce the boundary itself, the way pr_review.py refuses its own cross-owner writes.

require_write_scope now runs in main before the label is read, and only for the two writing subcommands, new and link:

Repository Writes
Under another owner Refused, with no gh call at all
Registered in registry/repos.json Allowed, with no extra request
Unregistered under the owner, a fork Allowed, after one gh repo view that the missing-label path reuses
Unregistered under the owner, not a fork Refused as registry drift

The write scope bounds no read. scripts/README.md and session-handoff are updated to match.

Verification

  • tests/test_handoff.py passes all 141 tests. A module-level patch now makes o/r a fleet repository by default, so existing write cases keep testing what they name. The new WriteScopeCase covers:
    • a labeled repository under another owner, for new and link;
    • a labeled, unregistered non-fork, for new and link;
    • a labeled, unregistered fork, which still files;
    • reads, which stay unbounded;
    • a registered repository, which costs no extra request.
  • Mutation checks each fail named tests: removing the scope call, the owner check, or the fork check; applying the scope to reads; dropping the cache.
  • The full unittest discover run passes (1944 tests). mypy, ruff, prose_lint --diff origin/develop, spec/validate.py, build_dist.py --check, and docker_lint.py are all clean.
  • local-strict-review: the first pass found 2 prose overclaims, both fixed. The second pass found nothing, and its receipt is recorded.

🤖 Generated with Claude Code

ptr727 and others added 2 commits October 1, 2026 15:57
Copilot's review of promotion #2254 found that the owner and fork checks ran
only where the handoff label was missing, so new or link against another
owner's repository went on to write whenever that repository carried a
handoff label, and an unregistered non-fork under the owner evaded the
registry-drift refusal the same way.

require_write_scope now runs before the label is read, for new and link
only. A repository under another owner refuses with no call at all, and an
unregistered repository of the owner's refuses unless it is a fork, the same
in-process owner boundary pr_review.py keeps. The reads stay open, and a
registered repository costs no extra request, since the fork answer is read
once a run and shared with the missing-label path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The local strict review found "the reads stay open everywhere" false, since
a read of an unlabeled repository under another owner still refuses on the
missing-label path, and the pr_review.py comparison overstated parity, since
that script reads its owner from origin and this one from the registry. Both
now say what the code does, and link against a labeled unregistered non-fork
gains its own case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 1, 2026 23:03
@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 074d7f26-3519-4ea2-9152-98c99adf4bad

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 57.31%. Comparing base (e0aeb72) to head (5ff97d2).

Files with missing lines Patch % Lines
scripts/handoff.py 95.23% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2266      +/-   ##
===========================================
+ Coverage    57.22%   57.31%   +0.08%     
===========================================
  Files           16       16              
  Lines         7595     7611      +16     
===========================================
+ Hits          4346     4362      +16     
  Misses        3249     3249              
Flag Coverage Δ
python-3.13 57.31% <95.23%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Fork writes must verify issue availability before proceeding; two minor prose nits also remain.

Review effort: Lite
Findings: None

What changed in this PR

This PR restricts handoff.py writes to authorized repositories while updating tests and documentation.

Changes:

  • Adds cached owner, registry, and fork validation before writes.
  • Expands regression coverage.
  • Updates canonical and generated handoff documentation.
File Summary
tests/​test_handoff.py Adds write-scope and caching coverage.
scripts/​README.md Documents write restrictions; one prose nit remains.
scripts/​handoff.py Enforces write scope; issue availability must also be checked for fork writes.
.github/​skills/​session-handoff/​SKILL.md Updates generated guidance.
.claude-plugin/​fleet-skills/​skills/​session-handoff/​SKILL.md Updates generated guidance.
.claude-plugin/​fleet-skills/​.source-digests/​session-handoff Refreshes the source digest.
.agents/​skills/​session-handoff/​SKILL.md Updates canonical guidance; one prose nit remains.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727

ptr727 commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Replies to the two notes in Copilot's overview:

  • "issue availability must also be checked for fork writes": declined, with evidence. An unregistered fork that already carries the label, and has issues turned off, reaches cmd_new. Its first write there is create(), which GitHub refuses. run_gh raises Execution, so the script exits 2 with gh's own stderr, and nothing is written. link's first call is issue view, a read that fails the same way before its body edit, comment, or close. A registered repository is not checked for issues either, so a separate check for forks would only reword an error that already stops before any change. The one path where an issues check prevents a write is --create-label, which would otherwise create a label ahead of an issue create that cannot succeed. That check has been in without_label since Keep the Fork Iteration PR Open and Let a Fork Host a Handoff Chain #2265.
  • "one prose nit remains" (scripts/README.md, .agents/skills/session-handoff/SKILL.md): the overview names no sentence and opens no thread, so there is nothing specific to act on. The changed sentences in both files were checked against the code by two local strict review passes, and the second found nothing.

@ptr727
ptr727 merged commit 18be0e9 into develop Oct 1, 2026
11 checks passed
@ptr727
ptr727 deleted the feature/handoff-write-boundary branch October 1, 2026 23:10
ptr727 added a commit that referenced this pull request Oct 2, 2026
…#2254)

## Summary

Promotes develop to main, carrying the pull requests below. Each was
already reviewed and merged into develop.

- [#2253](#2253): Track
Qodo's open-source login and state its star gate.
- [#2259](#2259): Give
install-tools a JSON report mode a program can read. Copilot could not
review it, since Copilot code review has reached its weekly rate limit
(#2261). CodeRabbit reviewed its head with no findings, and recorded
local passes covered every push.
- [#2263](#2263): Declare
Python and Codecov on Blog's registry entry.
- [#2265](#2265): Keep the
fork iteration PR open and never merged in
`upstream-contribution-workflow`, and let an unregistered fork under the
owner host a handoff chain, with `handoff.py new --create-label`
creating only the `handoff` label there.
- [#2266](#2266): Bound
`handoff.py`'s writes whatever the label state, refusing `new` and
`link` against another owner's repository, or an unregistered non-fork,
before the label is read. This answers Copilot's High finding on this
promotion.
- [#2267](#2267): State
the install-tools JSON report in `docs/host-setup.md`, answering
Copilot's previously-missed finding on #2259's report mode.
- [#2269](#2269): Drop two
false pointers from Blog's deploy-secret drift note, and recast every
semicolon in the registry's driftNotes, answering Copilot's
previously-missed finding on #2263's note.

With the open-source login tracked, `qodo_open` double-counts that app's
threaded findings and never clears them on PlexCleaner. That is a known,
loud error, accepted for this promotion and tracked in #2252.

Closes #1465
Closes #1645
Closes #2264

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Clarified which review commands to use when a reviewer posts a skip
notice.
* Updated reviewer evaluation guidance to reflect when CodeRabbit and
Qodo findings are recorded, including Qodo’s repository eligibility
requirements.
* **Bug Fixes**
* Updated Qodo reviewer tracking to recognize its current open-source
app identity, improving how its reviews and findings are identified.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants