Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
c45a452
docs: the triad split's lane-tooling side, surface by surface (T006, …
brettheap Oct 9, 2026
2aa8a59
WIP (untested): T018 worktree visibility for triad legs — the legs re…
brettheap Oct 9, 2026
5fcdf6a
T018 (a): the triad guidance for the sweep and lane-end's gate — READ…
brettheap Oct 9, 2026
8e2227e
WIP (untested): T018 (a) tests — tests/test_triad_lane_tooling.py and…
brettheap Oct 9, 2026
96da9af
WIP (untested): T010 docs — the §4.14 CI sketch exits 4 under #190's …
brettheap Oct 9, 2026
30f9dc0
T018 (c): the daily report counts each leg of an assembly as a checko…
brettheap Oct 9, 2026
13cb52d
T018 (d): lane-worktrees add records the leg it made a tree from, and…
brettheap Oct 9, 2026
4e39854
T018 (b): lane-handoff sees a triad's legs — the paired trees polled,…
brettheap Oct 9, 2026
9a5bbe2
T018 (b): lane-reconcile reads a triad's legs — each leg's worktree r…
brettheap Oct 11, 2026
e153361
Merge feat/triad-lane-tooling-handoff (T018 (b), writer 2): lane-hand…
brettheap Oct 11, 2026
b71e547
WIP (untested): T018 (b) guidance — README-lanes says what lane-hando…
brettheap Oct 11, 2026
9991d69
WIP (untested): T018 (d) — add's refusal on an unreadable manifest is…
brettheap Oct 11, 2026
8cb1368
Merge main f87fd5a into feat/triad-lane-tooling (T018): test the bran…
brettheap Oct 11, 2026
c9ffdce
WIP: checkpoint before account swap; done: #194 proving test written,…
brettheap Oct 11, 2026
9a29bbb
commit_push publishes the local commits a write with nothing staged f…
Oct 13, 2026
941330a
T018 docs: a parked paired tree is not the lane's to the sweep (§7 it…
Oct 13, 2026
4d4957d
T018 (b), pre-PR review M1 option (a): lane-handoff polls the paired …
Oct 13, 2026
352c1b6
test_commit_push_published_edit_194: the refusal case names a transcr…
Oct 13, 2026
6658396
T018 docs: README-lanes and the analysis say what M1 (a), S1 and S2 c…
Oct 13, 2026
836e1e1
#214 review: only `commit` publishes the commits a write with nothing…
Oct 13, 2026
fab2cbc
test_commit_push_published_edit_194: the no-op case asserts its behav…
Oct 13, 2026
7757eaa
Merge main aaa7bc8 into feat/triad-lane-tooling (T018): test the bran…
Oct 17, 2026
9f23a6b
WIP (untested): T018: lane-reconcile reports a leg whose .git git can…
Oct 17, 2026
bf2a220
WIP (untested): T018: lane-handoff counts a leg git cannot read as un…
Oct 17, 2026
f34c993
#214 adversarial check: `commit` reads the queue on the branch it pus…
Oct 17, 2026
cf7db4a
Merge main 2732d59 into feat/triad-lane-tooling (T018)
Oct 17, 2026
5d2c1c8
T018: lane-handoff withholds only a tree that could be an unreadable …
Oct 17, 2026
9a8f175
T018 docs: record lane 1's rulings of comment 6240800023 in the analy…
Oct 17, 2026
5b68127
Exit-code tables: say the #194 refusal pushes none of them, not "noth…
Oct 17, 2026
107958c
Merge main 83d2690 into feat/triad-lane-tooling (T018)
Oct 18, 2026
9f8aea8
#214 reviews (openRepoShape-2 6242165339, openRepoTools-3 6242725522)…
Oct 18, 2026
ee33a33
Say what the publish fence checks: register and handoff writes by pat…
Oct 18, 2026
69f0017
Merge main f595e44 into feat/triad-lane-tooling (T018)
Oct 18, 2026
a4e0b17
T018: the daily report lists a leg that is also a canonical clone onc…
Oct 18, 2026
a60cf1c
T018 docs: the analysis spells bench paths ~/projects/..., as the hyg…
Oct 18, 2026
88ee9d9
Merge main f5c3bcd into feat/triad-lane-tooling (T018)
Oct 18, 2026
656b191
#194: a publish the pull empties exits 0 and says so; pin the fence's…
Oct 18, 2026
3d0642c
T018: verify 88ee9d9: 224 passed, 1 failed (test_the_lane_helper_suit…
Oct 18, 2026
ea4db0d
T018 tests: the unreadable-leg tests ask the git under test what it s…
Oct 18, 2026
41433eb
Merge openRepoTools-4's #214 head 656b1914 as the stacked base of act…
Oct 18, 2026
ad0c031
Merge openRepoTools-1's #246 head ea4db0d1 as the stacked base of act…
Oct 18, 2026
ef16bbe
Merge openRepoTools main 586dea25 (#247, #237) into act 2's slice 1a …
Oct 18, 2026
d0010a2
WIP: every register write goes through its lane's own checkout <W>-la…
Oct 18, 2026
5dd0df0
Re-run CI on main fe58808: refs/pull/246/merge was stale on 14239b9
Oct 18, 2026
465df53
Merge openRepoTools main fe588082 (#204, #206, #208, #218, #220, #221…
Oct 18, 2026
129e201
Merge branch 'main' into fix/commit-push-publish-committed-edit
brettheap Oct 18, 2026
51efdb3
lane-start and lane-end read a lane's row in its own register checkou…
Oct 18, 2026
59b39df
The shell suite's #67 cases (from main's #221, issue #67) name their …
Oct 18, 2026
eff9107
Merge branch 'main' into fix/commit-push-publish-committed-edit
brettheap Oct 18, 2026
fcf7f48
Merge #214's final head eff9107b (its refresh over main 08e7550) into…
Oct 19, 2026
0d4ade8
Merge #214's squash 9b94a597 into act 2's slice 1a with -s ours: its …
Oct 19, 2026
fda7808
tests/test_lanes_index.py: its Estate names its old W by the explicit…
Oct 19, 2026
6d22d0b
Merge openRepoTools main b707bd70 into act 2's slice 1a (#198)
Oct 19, 2026
eb9eb74
Merge #246's final head 5dd0df07 into act 2's slice 1a (#198)
Oct 19, 2026
9d26089
Merge #246's squash 55aae16 into act 2's slice 1a with -s ours: the b…
Oct 19, 2026
18f5155
Merge openRepoTools main f18b818 (#252, #264, #266, #283, #262, #267-…
Oct 20, 2026
874e020
Fix round 1 of #282 (lane 3's review): routing is opt-in until slice …
Oct 20, 2026
ecb96ed
Fix round 1's surviving mutants are killed: 12 cases pin the opt-in g…
Oct 20, 2026
eead86d
Fix round 2 of #282 (lane 3's re-review): without the opt-in a lock i…
Oct 20, 2026
15c8e3f
Fix round 3 of #282 (lane 3's re-check of eead86d): without the opt-i…
Oct 20, 2026
6ca3158
SC2093: mark 1a's routing exec as deliberate, as lane openRepoTools-3…
Oct 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion lane-end
Original file line number Diff line number Diff line change
Expand Up @@ -523,11 +523,18 @@ lanes_workspace_why() {
# — so `$SCRIPT_DIR` answers both without a second rule. `$OPENREPOTOOLS_BIN_DIR`
# and `$PATH` are the fallbacks for a command copied somewhere on its own.
LANES_WS_ROOT=""
# AMENDMENT 23 (act 2, slice 1a). With neither variable set, every write of a
# lane goes through that lane's own register checkout, and the register this
# command READS follows it there once the lane's name is known
# (`lane_register_follow`, below). A caller's `LANES_REPO` without `LANES_FILE`
# is the checkout the helper now writes in, so its own register is the one read.
LANES_REG_DEFAULT=0
[ -n "${LANES_FILE:-}" ] || [ -n "${LANES_REPO:-}" ] || LANES_REG_DEFAULT=1
if [ -z "${LANES_FILE:-}" ] || [ -z "${LANES_REPO:-}" ]; then
LANES_WS_ROOT="$(lanes_workspace_root || :)"
fi
: "${LANES_REPO:=$LANES_WS_ROOT}"
LANES_FILE="${LANES_FILE:-${LANES_WS_ROOT:+$LANES_WS_ROOT/lanes/LANES.md}}"
LANES_FILE="${LANES_FILE:-${LANES_REPO:+$LANES_REPO/lanes/LANES.md}}"

lanes_edit_default() {
local d
Expand Down Expand Up @@ -940,6 +947,52 @@ if [ "$cl_rc" = 0 ] && [ -n "$cl_out" ] && [ "$cl_out" != "$LANE" ]; then
LANE="$cl_out"
fi

# AMENDMENT 23 S1, S2 — THE REGISTER THIS COMMAND READS IS THE ONE ITS WRITES GO
# THROUGH. Under `LANES_ROUTE_WRITES=1` (opt-in until slice 1b, the review of
# #282's MUST 2) and the default resolution, every write of this lane goes
# through its own checkout, `<W>-lanes/<lane>/`, and W, the readers' copy, moves
# only by `lanes-edit.sh refresh-workspace`. So W's working tree does not carry the
# lane's own rows once they are written: a lane started through its checkout
# read as a lane with no row, and a second start refused to add a duplicate
# that W could not see. The row this command counts and acts on is therefore
# read from that checkout. The helper makes the checkout here if it is not
# there yet, exactly as this command's first write would; a dry run makes
# nothing and reads W where there is no checkout. ONLY THE READ MOVES: the
# handoff this command publishes is still W's until Amendment 23's later slices.
# A helper that predates the verb writes W itself, so W is what is read. A
# checkout that could not be made (2) or whose creation lock is held (4) is
# SAID, and W is read (SHOULD 2): Amendment 8(d) — a launch is never refused for
# a register act it can do without, and the writes after it say their own.
lane_register_follow() {
[ "${LANES_ROUTE_WRITES:-}" = 1 ] || return 0
[ "$LANES_REG_DEFAULT" = 1 ] && [ -n "${LANE:-}" ] || return 0
case "$prog" in lane-end) lrf_none="Nothing was written." ;; *) lrf_none="Nothing was launched, renamed or written." ;; esac
lrf_args=(lane-checkout "$LANE")
[ "${dry_run:-0}" = 1 ] || lrf_args+=(--create)
lrf_errf="$(mktemp "${TMPDIR:-/tmp}/${prog}-register.XXXXXX" 2>/dev/null || printf '')"
lrf_out=""; lrf_rc=0
lrf_out="$("$LANES_EDIT" "${lrf_args[@]}" 2>"${lrf_errf:-/dev/null}")" || lrf_rc=$?
lrf_err=""
if [ -n "$lrf_errf" ]; then lrf_err="$(cat -- "$lrf_errf" 2>/dev/null || :)"; rm -f -- "$lrf_errf"; fi
case "$lrf_rc" in
0)
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
[ -f "$lrf_out/lanes/LANES.md" ] ||
die "lane $LANE's register checkout $lrf_out carries no lanes/LANES.md, so the lane's row cannot be read (Amendment 23 S1). $lrf_none" 1
LANES_FILE="$lrf_out/lanes/LANES.md" ;;
8) : ;; # a dry run, and no checkout yet: W is what there is
2 | 4)
case "$lrf_err" in *"unknown subcommand 'lane-checkout'"*) return 0 ;; esac
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
note "lane $LANE's own register checkout could not be made (\`$LANES_EDIT lane-checkout $LANE --create\` exited $lrf_rc, above), so this command reads W's register, which may not show what this lane's earlier writes put there (Amendment 23 S1, 8(d)). Each write below says for itself whether it went through." ;;
*)
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
die "lane $LANE's own register checkout could not be read (\`$LANES_EDIT lane-checkout $LANE\` exited $lrf_rc, above), so the row this command acts on cannot be read where its writes go (Amendment 23 S1). $lrf_none" 1 ;;
esac
return 0
}
lane_register_follow

# THE SEAM (ruling 2026-10-04): A MANAGED-OWNED LANE IS NOT THIS COMMAND'S.
# `lanes-edit.sh managed-projection` answers 0 with the owner where the lane's
# register row carries the managed ledger's marker, 8 for a legacy lane, and 1
Expand Down
63 changes: 61 additions & 2 deletions lane-start
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,18 @@ lanes_workspace_why() {
# — so `$SCRIPT_DIR` answers both without a second rule. `$OPENREPOTOOLS_BIN_DIR`
# and `$PATH` are the fallbacks for a command copied somewhere on its own.
LANES_WS_ROOT=""
# AMENDMENT 23 (act 2, slice 1a). With neither variable set, every write of a
# lane goes through that lane's own register checkout, and the register this
# command READS follows it there once the lane's name is known
# (`lane_register_follow`, below). A caller's `LANES_REPO` without `LANES_FILE`
# is the checkout the helper now writes in, so its own register is the one read.
LANES_REG_DEFAULT=0
[ -n "${LANES_FILE:-}" ] || [ -n "${LANES_REPO:-}" ] || LANES_REG_DEFAULT=1
if [ -z "${LANES_FILE:-}" ] || [ -z "${LANES_REPO:-}" ]; then
LANES_WS_ROOT="$(lanes_workspace_root || :)"
fi
: "${LANES_REPO:=$LANES_WS_ROOT}"
LANES_FILE="${LANES_FILE:-${LANES_WS_ROOT:+$LANES_WS_ROOT/lanes/LANES.md}}"
LANES_FILE="${LANES_FILE:-${LANES_REPO:+$LANES_REPO/lanes/LANES.md}}"

lanes_edit_default() {
local d
Expand Down Expand Up @@ -1157,6 +1164,52 @@ esac
repo="${repo:-$LANE}" # the verbatim form has no <repo> of its own
estate="${estate:-$repo}"

# AMENDMENT 23 S1, S2 — THE REGISTER THIS COMMAND READS IS THE ONE ITS WRITES GO
# THROUGH. Under `LANES_ROUTE_WRITES=1` (opt-in until slice 1b, the review of
# #282's MUST 2) and the default resolution, every write of this lane goes
# through its own checkout, `<W>-lanes/<lane>/`, and W, the readers' copy, moves
# only by `lanes-edit.sh refresh-workspace`. So W's working tree does not carry the
# lane's own rows once they are written: a lane started through its checkout
# read as a lane with no row, and a second start refused to add a duplicate
# that W could not see. The row this command counts and acts on is therefore
# read from that checkout. The helper makes the checkout here if it is not
# there yet, exactly as this command's first write would; a dry run makes
# nothing and reads W where there is no checkout. ONLY THE READ MOVES: the
# handoff this command publishes is still W's until Amendment 23's later slices.
# A helper that predates the verb writes W itself, so W is what is read. A
# checkout that could not be made (2) or whose creation lock is held (4) is
# SAID, and W is read (SHOULD 2): Amendment 8(d) — a launch is never refused for
# a register act it can do without, and the writes after it say their own.
lane_register_follow() {
[ "${LANES_ROUTE_WRITES:-}" = 1 ] || return 0
[ "$LANES_REG_DEFAULT" = 1 ] && [ -n "${LANE:-}" ] || return 0
case "$prog" in lane-end) lrf_none="Nothing was written." ;; *) lrf_none="Nothing was launched, renamed or written." ;; esac
lrf_args=(lane-checkout "$LANE")
[ "${dry_run:-0}" = 1 ] || lrf_args+=(--create)
lrf_errf="$(mktemp "${TMPDIR:-/tmp}/${prog}-register.XXXXXX" 2>/dev/null || printf '')"
lrf_out=""; lrf_rc=0
lrf_out="$("$LANES_EDIT" "${lrf_args[@]}" 2>"${lrf_errf:-/dev/null}")" || lrf_rc=$?
lrf_err=""
if [ -n "$lrf_errf" ]; then lrf_err="$(cat -- "$lrf_errf" 2>/dev/null || :)"; rm -f -- "$lrf_errf"; fi
case "$lrf_rc" in
0)
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
[ -f "$lrf_out/lanes/LANES.md" ] ||
die "lane $LANE's register checkout $lrf_out carries no lanes/LANES.md, so the lane's row cannot be read (Amendment 23 S1). $lrf_none" 1
LANES_FILE="$lrf_out/lanes/LANES.md" ;;
8) : ;; # a dry run, and no checkout yet: W is what there is
2 | 4)
case "$lrf_err" in *"unknown subcommand 'lane-checkout'"*) return 0 ;; esac
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
note "lane $LANE's own register checkout could not be made (\`$LANES_EDIT lane-checkout $LANE --create\` exited $lrf_rc, above), so this command reads W's register, which may not show what this lane's earlier writes put there (Amendment 23 S1, 8(d)). Each write below says for itself whether it went through." ;;
*)
[ -z "$lrf_err" ] || printf '%s\n' "$lrf_err" >&2
die "lane $LANE's own register checkout could not be read (\`$LANES_EDIT lane-checkout $LANE\` exited $lrf_rc, above), so the row this command acts on cannot be read where its writes go (Amendment 23 S1). $lrf_none" 1 ;;
esac
return 0
}
lane_register_follow

# ----------------------------------------- 1b. THE LANE'S DIRECTORY
#
# AMENDMENT 11 CLAUSE (c). A lane's checkout is known to every process that is
Expand Down Expand Up @@ -4255,7 +4308,13 @@ hs_git_net() {
# `lanes-edit.sh` write goes out of it. Promising a carry that will not happen
# is worse than printing the command, so the note says which it is.
hs_carry_note() {
if [ -n "${LANES_REPO:-}" ] && [ "$hs_repo" = "$LANES_REPO" ]; then
# UNDER `LANES_ROUTE_WRITES=1` NO WRITE GOES OUT OF W (Amendment 23 S2; the
# review of #282, SHOULD 6): with the default resolution each one goes through
# its lane's own checkout, so none will ever push a commit made here.
if [ "${LANES_ROUTE_WRITES:-}" = 1 ] && [ "$LANES_REG_DEFAULT" = 1 ] &&
[ -n "${LANES_REPO:-}" ] && [ "$hs_repo" = "$LANES_REPO" ]; then
note " (this handoff is in W ($hs_repo), and under LANES_ROUTE_WRITES=1 every lanes-edit.sh write goes through its lane's own checkout instead, so none will push this commit: the command above is the whole of the recovery.)"
elif [ -n "${LANES_REPO:-}" ] && [ "$hs_repo" = "$LANES_REPO" ]; then
note " (this handoff is in the register's own checkout, so the next lanes-edit.sh write out of it pushes the branch and carries this commit with it.)"
else
note " (this handoff is NOT in the register's checkout ($hs_repo), so no lanes-edit.sh write will ever push it: the command above is the whole of the recovery.)"
Expand Down
35 changes: 35 additions & 0 deletions lane-worktrees
Original file line number Diff line number Diff line change
Expand Up @@ -5519,7 +5519,24 @@ class Report:

def _foreign(self, clones: list, canonical: list) -> None:
rows = []
# AMENDMENT 23 S1 - A LANE'S REGISTER CHECKOUT IS NOT A STRAY CLONE (the
# review of opensoft/openRepoTools#282, SHOULD 5). `<W>-lanes/<lane>/` is
# a clone of the register's origin beside W, made on purpose and holding
# that lane's writes; listing it here told a person to dispose of it.
wroot = self.helper.workspace_root() if self.helper.path else ""
lanes_home = real(wroot) + "-lanes" if wroot else ""
# AND A W THAT IS ITSELF A LANE CHECKOUT (the re-review of #282, SHOULD
# 5): Eagle's lane windows resolve W to their own `<X>-lanes/<lane>/`,
# and lane-start runs this report from there. Its lanes home is then its
# parent, as lanes-edit.sh's `lanes_home_check` reads a `*-lanes` one.
home = os.path.dirname(real(wroot)) if wroot else ""
if len(os.path.basename(home)) > len("-lanes") and home.endswith("-lanes"):
lanes_home = home
registers = []
for c in clones:
if lanes_home and os.path.dirname(real(c)) == lanes_home:
registers.append(c)
continue
container = _under_container(c, self.root)
why = ""
if container:
Expand All @@ -5541,6 +5558,24 @@ class Report:
("LOAD-BEARING: " + _lean_text(lean)) if lean else ""])
self.add("FOREIGN repositories", rows, "none: every clone is the estate's own checkout",
"A lane creates worktrees, never clones. Each is a person's to dispose of.")
if registers:
self._register_checkouts(registers)

def _register_checkouts(self, registers: list) -> None:
"""Amendment 23 S1: each lane's own checkout of the register, reported
with what it holds that origin lacks, and never offered for disposal."""
rows = []
for c in registers:
last = git_out(c, "log", "-1", "--date=short", "--format=%cd") or "?"
ahead = git_out(c, "rev-list", "--count", "origin/main..HEAD")
held = ("its HEAD could not be compared with origin/main" if ahead is None else
f"{ahead} commit(s) origin/main lacks" if ahead != "0" else "")
rows.append([c, f"lane {os.path.basename(c)}", human_size(dir_size(c)), last, held])
self.add("Register checkouts (Amendment 23 S1)", rows, "none",
"Each is one lane's own checkout of the register, where its writes go, and "
"not a stray clone: lane-end's sweep retires one (Amendment 23 S6), and a "
"person moves one aside only once `git -C <path> cherry -v origin/main` "
"shows nothing.")

def _closed_lanes(self) -> dict:
"""{lane: why} for every lane whose snapshot is CLOSED or whose log's
Expand Down
Loading
Loading