Repository navigation
Amendment 23 act 2, slice 3: the handoff skill locates its file with handoff-path and writes it with ONE write-handoff --whole call from the lane's own checkout, so it spells, commits in, pulls and pushes no checkout of its own (#198) - #311
Draft
brettheap wants to merge 1 commit into
Draft
brettheap wants to merge 1 commit into
brettheap wants to merge 1 commit into
Conversation
…gh `handoff-path` and writes it with ONE `write-handoff --whole` call, so it spells no checkout and commits, pulls and pushes nothing of its own, and step 4's `append-line` and `set-row-state` carry `LANES_LANE` (#198) Lane: openreposhape-2 (openRepoShape-2) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideThe PR changes the handoff skill from independently locating, committing, pulling, and pushing a checkout to preparing the full handoff and delegating one lane-scoped, digest-guarded Sequence diagram for the lane-scoped handoff writesequenceDiagram
participant Skill as HandoffSkill
participant Helper as lanes-edit.sh
participant LaneCheckout as LaneCheckout
participant Origin as Origin
Skill->>Helper: handoff-path lane --create
Helper-->>Skill: handoff_file
Skill->>Skill: Read prior_sha256 and prepare complete file
Skill->>Helper: write-handoff lane --whole prepared_file --expect-digest prior_sha256 --subject hf_subject
Helper->>LaneCheckout: Lock, sync, verify digest, atomically replace, commit
LaneCheckout->>Origin: Push handoff commit
Origin-->>LaneCheckout: Read back published handoff
LaneCheckout-->>Helper: Exit status and write result
Helper-->>Skill: stdout path/digest or refusal details
Skill->>Skill: Report result and continue swap
Flow diagram for handoff refusal handlingflowchart TD
A[Locate handoff with handoff-path --create] --> B{File and digest available?}
B -- No --> C[Print HANDOFF NOT FOUND]
C --> D[Continue swap without write-handoff]
B -- Yes --> E[Prepare complete handoff file]
E --> F{Prepared file is non-empty?}
F -- No --> G[Print HANDOFF NOT WRITTEN]
G --> D
F -- Yes --> H[Call write-handoff once with --whole and --expect-digest]
H --> I{Verb exit}
I -- 0 --> J[Report handoff written]
I -- 2 --> K[Report refusal; file may be written but uncommitted]
I -- 3 --> L[Report pushed but not confirmed]
I -- 6 --> M[Report commit kept on lane checkout]
I -- 7 --> N[Report digest conflict or restart ownership]
I -- Other --> O[Report not published]
J --> D
K --> D
L --> D
M --> D
N --> D
O --> D
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
This was referenced Oct 22, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Lane: openreposhape-2 (openRepoShape-2)
Claim: #198 (comment)
Slice 3 of Amendment 23 act 2:
skills/handoff/SKILL.mdstops committing, pulling and pushing the handoff itself. It says where the lane's handoff is withhandoff-path, reads the digest of what is there, and writes the complete new file with ONEwrite-handoff --wholecall, which slice 2a added. The block it replaces was one of the three writers that commit to a checkout with no lock and then pull and push (finding 282 of lane openRepoTools-3's review of #307, withlane-start's stamp andlane-handoff's PAUSED commit). The other two are slice 2b's.Stacked on
Slice 2a's branch
feat/198-a23-slice-2a-handoff-verbsate2037b9, the head this branch was cut from. This PR's own diff isgit diff e2037b9 HEAD: one commit,b599ed9, two files. Slice 2a stacks on slice 1b (#307, a draft whose review asks for changes before it lands) and slice 1a (#282).e2037b9. Origin's branch is now at2a41e83: A47, A48 and A49. They touchlanes-edit.sh,docs/README-lanes.mdandtests/test_a23_write_handoff.pyand no file of this slice. This branch has not merged them. The new module passed with A47's and A48's three files overlaid (68014b4, 61 passed). A49 adds tests totests/test_a23_write_handoff.pyfrom its line 789 on, below itsBoxclass (line 91) and the other names the new module imports from it, so the module's own fixtures are not touched by it. The new module has not been run with A49.83d2690,235c68aand2732d59, with Make every shell block in the handoff skill parse, and stop calling /rename the only act there is (#78, #79) #200 asf5c3bcd), so what is open is 2b (lane-startandlane-handoff; its branch on origin is a-wipref so far) and the three slices under it. openRepoTools main is frozen at33ce26duntil the cutover and act 2 has no merge word, so this PR is for review, not for landing.Decisions
F1 to F9 are numbered as the work's own log numbers them. F2 and F7 are the two that depart from the plan.
F1. Two blocks in step 2, and the verb is called once. The plan's one call needs the prior digest read BEFORE the session writes the complete new file, and the call itself comes AFTER the top block's template. So:
handoff_file="$("$L" handoff-path "$lane" --create)") sits after the paragraph that stops the swap's step where$handoffcame back empty. It defineshandoff_file,prior_sha256(sha256sum, elseshasum -a 256, shape-checked as 64 hex digits) andprepared_file(mktempunder$TMPDIR), and prints all three;--whole "$prepared_file") stands where Handoff skill: commit the handoff in the checkout it was published in, by its own path, and refuse foreign staged entries and in-progress operations (#197) #199's block stood. It buildshf_subjectand makes the ONE callLANES_LANE="$lane" "$L" write-handoff "$lane" --whole "$prepared_file" --expect-digest "$prior_sha256" --subject "$hf_subject".The old
publish-handoffblock (the plan's:209) is gone, and the three variables it named, which no step of the file ever defined, are now defined.F2. DEPARTS FROM THE PLAN:
handoff-path "$lane" --create, where the plan says a barehandoff-path "$lane". The skill must READ the file: for the digest, and for the old bytes the new file keeps under---. A barehandoff-pathnames a path in a checkout that may not exist yet, because a lane that never wrote through its own checkout has none.--createishandoff-path's own flag (2a's decision 9), and it is moot where routing is off orLANES_REPOis explicit. Question 1.F3. A handoff that is not found does not stop the swap (
R-A11-11). Block 1 printsHANDOFF NOT FOUND, emptieshandoff_file, and block 2's guard (handoff_file,prior_sha256and a non-emptyprepared_file) printsHANDOFF NOT WRITTEN ... was NOT called. Steps 3 to 5 still run. The existing "if$handoffcame back empty, stop here" paragraph is kept: that is a row that does not split, which is a different case.F4. Every exit of the verb is said, and none stops the swap. Block 2's
case:handoff written;HANDOFF NOT COMMITTED. The file is written and uncommitted; do not call again, because a second--wholeis refused (7);HANDOFF NOT WRITTEN;PUSHED, NOT CONFIRMED;NOT PUSHED, the commit kept on HEAD and named;NOT WRITTEN. The handoff moved, or a restart owns it. Retry only if it moved;NOT PUBLISHED, and whether the file is written.A non-empty stdout means the file is written:
cleanupprintsHANDOFF_OUTon every exit once it is set.F5. The subject is built from variables, never from placeholders (the rule of Copilot's review of workBenches#91 against the vendored bytes at f98d734: --dir flag swallows -*, lane-handoff's rename-before-commit and permissive window checks, --lane= accepts empty, and two placeholder leaks in handoff/SKILL.md #80's item 7):
handoff(and the lane, then an at sign and the workstation (nonewhere step 1 found none), then): PAUSED,and the why in the operator's words (handoffwhere there is none). Control characters are removed (LC_ALL=C tr -d '[:cntrl:]'), because the verb exits 64 on one and a tab in a why would cost the swap its handoff. The em dash survives.F6. The skill spells no checkout path at all. The file holds no
~/projects/brett-wip, noworkspace-root, noLANES_REPO, noLANES_BRANCHand nocdcommand. No line anywhere sayspullwith--rebase, so the file can join hygiene's_NO_PULL_FILES(F7).F7. DEPARTS FROM THE PLAN:
_NO_PULL_FILESintests/test_repo_hygiene.pyis NOT edited here. The plan wantsskills/handoff/SKILL.mdin that tuple, but slice 2b edits the same tuple line forlane-startandlane-handoff, so two slices would conflict on one line by construction. The new module carriestest_the_skill_never_pulls_with_rebase_outside_a_comment, which holds the same rule with the same pattern. The third name goes in at the merge of 2b. Question 2.F8. Step 4:
append-lineandset-row-statenow run asLANES_LANE="$lane" "$L" ....log PAUSEDalready did. A comment in the block names why: under Amendment 23 S2 a register write goes through the lane's own checkout, andappend-linefinds its lane from the variable first, so a line that names no lane with a row is not a write with no lane.F9. The tests are one rewritten module,
tests/test_handoff_skill_commit_block.py(61 tests, each of the blocks underbashand underzshwhere it is installed). See "Tests".What changed
skills/handoff/SKILL.md(99 lines added, 61 removed):Lane:trailer, the push with no pull, the read-back and the replay of a refused push, and that the skill holds no lock and runs nogit. Thepublish-handoffcall and its sentence about the explicit-pathspec commit are gone.$LANES_REPOand thenworkspace-root; the refusals for an operation in progress and for a staged entry the handoff did not make;git addandgit commitby pathspec;git pull --rebase origin ${LANES_BRANCH:-main}andgit push;rebase --abort. The refusals are the verb's own now, made before anything is committed (2), and a handoff that moved after its digest was read is exit 7 with nothing published.R-A11-11, a swap is never left unwritten, and says what the verb does on a refusal (2) and on a refused push (replay where origin's copy of the handoff is still the one this write was made from, otherwise the commit is kept on HEAD and named, 6).git add ""that went with Handoff skill: commit the handoff in the checkout it was published in, by its own path, and refuse foreign staged entries and in-progress operations (#197) #199's block.tests/test_handoff_skill_commit_block.py, rewritten (489 lines added, 382 removed). It was Handoff skill: commit the handoff in the checkout it was published in, by its own path, and refuse foreign staged entries and in-progress operations (#197) #199's tests of a block that resolved a checkout and committed in it. It is now 61 tests of the two blocks above.Tests
One pytest process per run, with every
LANES_*,TMUX*,CLAUDE_*andGIT_*variable unset, a refusingghstub first on PATH,GH_TOKEN=bogus,GIT_SSH_COMMAND=falseandGIT_CONFIG_GLOBAL=/dev/null. Nothing reached a real register, W or GitHub. The two files below were run on a tree whoseSKILL.mdand test module are byte-identical tob599ed9's (sha256 compared with the commit's files).tests/test_handoff_skill_commit_block.pyb599ed9's bytestests/test_handoff_skill_98_99_100.pyb599ed9's bytestests/test_handoff_skill_80_85.py,tests/test_handoff_skill_72_80.pyandtests/test_skill_shell_blocks.py, one processb599ed9's bytestests/test_repo_hygiene.pyb599ed9's bytestests/test_handoff_skill_commit_block.py, with 2a'slanes-edit.sh,docs/README-lanes.mdandtests/test_a23_write_handoff.pyfrom68014b4overlaid in a copyb599ed9plus those three filesThe 61 tests of the module:
test_block_calls_write_handoff_with_whole_and_expect_digest(2): the stublanes-edit.shanswershandoff-pathandwrite-handoffand logs its argv, itsLANES_LANEand the prepared file's bytes; the call is--whole <prepared> --expect-digest <sha> --subject <s>and nothing else;test_no_spelled_checkout_and_no_workspace_root_fallback(2);test_step4_writes_carry_LANES_LANE(4), with the ambientLANES_LANEunset and set to another lane;test_refusal_text_keeps_R_A11_11;write-handoffis called once.write-handoffis never called (8, four shapes).--rebase, every block parses underbash -n, the refusal text keepsR-A11-11, and every register write and the handoff write names its lane.lanes-edit.sh(10 tests, in slice 2a'sBox: a bare origin, W, the lane's row and handoff,LANES_ROUTE_WRITES=1, aghand atmuxthat refuse):Lane:trailer, and W is untouched: its HEAD, its status, its reflog, and a foreign entry STAGED in W stays staged and unpublished. Routed and through the managed seam, in both shells (4);HANDOFF NOT FOUND, and nothing is cloned (2).Not run here. The shell suite (
tests/test_lane_helpers_suite.py) and the whole oftests/test_supervised_restart_regressions.py; CI'stestsjob is the suite of record. One static check stands in for the part of the shell suite that reads this skill: a script compared, ate2037b9and at this head, every single-line string thattests/test_lane_helpers.shaskshasorhasntof the skill (26 on$hfskand 18 on$SWSK_TEXT). Every answer is the same at both heads, step 4'sset-row-state "$lane" ...line included. No test other than the ones above pins the skill's bytes:tests/test_tests_workflow.py,tests/test_openrepotools_command.pyandtests/test_install_skill_and_hook.pyname the file but read it at run time, and thepyproject.tomlentry is a path map. Those three were read, not run.Mutants
15 one-line mutants of
skills/handoff/SKILL.md, each applied to agit archivecopy ofb599ed9and run against the module with-x, so each stops at the first test to fail. All 15 were killed.--expect-digesttest_block_calls_write_handoff_with_whole_and_expect_digest[bash]append-linewithoutLANES_LANEtest_step4_writes_carry_LANES_LANE[unset-bash]workspace-rootfallback backtest_no_spelled_checkout_and_no_workspace_root_fallback[bash]--createtest_block_calls_write_handoff_with_whole_and_expect_digest[bash]trtest_the_subject_is_one_line_with_no_control_character[control-characters-removed-bash]pushedtest_each_exit_of_the_verb_is_said_and_the_swap_goes_on[refused-after-writing-bash]write-handoffwithoutLANES_LANEtest_block_calls_write_handoff_with_whole_and_expect_digest[bash]set-row-statewithoutLANES_LANEtest_step4_writes_carry_LANES_LANE[unset-bash]pull --rebaselinetest_no_spelled_checkout_and_no_workspace_root_fallback[bash]-smade-ntest_a_prepared_file_the_session_never_wrote_is_never_sent[bash]test_each_exit_of_the_verb_is_said_and_the_swap_goes_on[moved-or-owned-bash]test_block_calls_write_handoff_with_whole_and_expect_digest[bash]cdto the checkouttest_no_spelled_checkout_and_no_workspace_root_fallback[bash]publish-handoffbacktest_block_calls_write_handoff_with_whole_and_expect_digest[bash]--wholetest_block_calls_write_handoff_with_whole_and_expect_digest[bash]Six of the 15 (m1, m4, m7, m12, m14 and m15) are killed by the one argv test, which is the test built to pin the call. Each mutant was killed in the
basharm, and thezsharm reads the same text. No mutant of the integration tests was run.Questions for lane openRepoTools-3
handoff-path "$lane" --create, not the plan's bare call (F2). Step 2 reads the file for its digest and for the old bytes the new file keeps, so a barehandoff-paththat names a path in a checkout nobody has cloned yet would leave nothing to read, for a lane whose first write this is. Is it right that a read at step 2 makes the lane's checkout, or should the skill make the bare call and sayHANDOFF NOT FOUNDwhere the file is not there?_NO_PULL_FILESis left for the merge of 2b (F7). The tuple line is one both slices edit. Is it right to addskills/handoff/SKILL.mdto it as one word in 2b's merge, with this module's own regex test holding the rule until then?write-handoff --wholeexit 7. The skill reads the digest from the file in the checkout, and the verb brings the checkout to origin only after that, under its lock. Where origin holds a newer handoff than the checkout does, the digest names bytes that the verb's own sync then replaces. The skill says what to do on 7 (read it again, make the new file from what is there, call once more), so no handoff is lost, but the first call of such a swap is wasted. The integration test of a peer's edit between the digest and the call shows the exit (7, nothing published, the block says to read it again); a checkout that is already behind gets it every time, not by a race, and no test makes that case on its own. Shouldhandoff-path --createbring the checkout to origin when it makes it or finds it behind, so that the first call matches?lanes-edit.shhas nohandoff-path: the helper answers "unknown subcommand", block 1 printsHANDOFF NOT FOUNDand the swap goes on with no handoff refreshed. Distribution isopenRepoTools --install, which writes the skill to~/.claude-profiles/shared/skills/handoff/SKILL.mdand~/.claude/skills/handoff/SKILL.md, and opensoft/workBenches vendors a copy (named in skills/handoff/SKILL.md:310-315: the handoff commit is a baregit commitin a spelled ~/projects/brett-wip, so it can publish other lanes' staged work and stop mid-rebase: resolve the checkout, commit by pathspec, refuse foreign staged entries #197); none was touched or run here. Should the cutover put the helper (2a and 2b) in place before the skill, and should block 1 say "updatelanes-edit.sh" where the helper does not know the verb?Not changed
lane-start,lane-handoffandlane-endare as they were. Slice 2b makes thewrite-handoffandhandoff-pathcalls of the first two, and slice 4 islane-end's.lanes-edit.shanddocs/README-lanes.mdare slice 2a's and untouched here (the manual says only that the skill is the single source of the act).tests/test_repo_hygiene.py's_NO_PULL_FILES(F7).log PAUSEDwrite, which already carriedLANES_LANE.skills/lane-swap/SKILL.md, the alias, which restates no step.openRepoTools --installor--uninstall, and nothing under~/.claudeor~/.claude-profiles/sharedwas edited.Refs #198
🤖 Generated with Claude Code
Summary by Sourcery
Delegate complete handoff publication to one lane-aware helper call and keep the handoff skill from managing checkouts or Git operations itself.
Bug Fixes:
Enhancements:
write-handoff --wholeoperation with digest protection and explicit handling for write, commit, push, and concurrency outcomes.Tests: