From 454f062c13a521153c8d033dd451772b1c36cae2 Mon Sep 17 00:00:00 2001 From: Brett Heap <1513478+brettheap@users.noreply.github.com> Date: Sat, 31 Oct 2026 19:58:23 +0000 Subject: [PATCH] A lane whose recorded dir holds a TAB or a backslash is now listed, indexed and reached as recorded, a stored sub-field reads back as it was written, and request-handoff refuses a host or container the binding fence rejects This is the T017 continuation, in this leg (opensoft/openRepoTools-spec), of the original opensoft/openRepoTools branch fix/subfield-misreads-301 at f68030f466ad49c81f02edf8f21a58423a7f8173, issue opensoft/openRepoTools#301. The original is stacked on fix/dir-space-listing-295 (opensoft/openRepoTools#295, head e0970a808af5), so its own change is its head against that head; opensoft/openRepoTools#295 has no path in this leg. Spec-leg part of its own change: docs/README-lanes.md (+1 -1, the lanes row of the reads table, which now names the escape on column 7). Its other paths (lane, lanes, lanes-edit.sh and tests/test_subfield_misreads_301.py) belong to the code leg and are the paired commit there; the leg table sends docs/ to this leg with no rename. The subjects below are quoted from the originals; a bare #N in them is opensoft/openRepoTools#N. Old-to-new receipt, the original's own non-merge commits in opensoft/openRepoTools (e0970a8..f68030f): 773a562bccd1 Add the tests that a recorded dir holding a TAB or a backslash, and a requesting host holding a space, are read back as they were written (#301) dd361f3839cf The #301 tests split the listings they read on a newline alone, not on every line boundary Python knows (#301) 430ac8f0804b The lane listing escapes a lane's directory in its seventh column as lane-worktrees' porcelain escapes a field, and lanes-edit.sh, lane and lanes decode it, so a TAB in a recorded dir no longer shifts the row (#301) 647f4511b210 request-handoff refuses a requesting host that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301) ae14da06a53f payload_subfield hands the payload to awk through ENVIRON instead of awk -v, so a stored sub-field holding a backslash reads back as it was written (#301) c0491f1db6f6 Pin what item 2 moves: lane-start reaches a backslash lane's own checkout, lane-handoff writes its dir back byte for byte, and its lifecycle starts again at the new root while the index holds the old rows (#301) 567035fec28b request-handoff refuses a container that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301) 27253fe78a10 The #301 tests pin a carriage return in a recorded dir and the decoders' pass-through arm, and the lanes_rows contract comment says column 7 is escaped (#301) e1d26e135cec The #301 tests now pin the fallback for a dir the encoder cannot escape, where a refused name came from, the free-lane answer before a bad host, and a container of the fence's alphabet (#301) f68030f466ad The #301 tests now pin a capital letter in the binding fence's whole-alphabet row and pin that a free lane's request leaves the published register where it was (#301) Lane: openRepoTools-4 Co-Authored-By: Claude Sonnet 5.5 --- docs/README-lanes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README-lanes.md b/docs/README-lanes.md index e012075..c2c3c72 100644 --- a/docs/README-lanes.md +++ b/docs/README-lanes.md @@ -1736,7 +1736,7 @@ falls to its next rung there rather than refusing. | `lanes-edit.sh session-lane ` | the lane whose register row's **session cell** names that transcript uuid. Adoption act 0's; it is the read the `SessionStart` hook already made. **0** the lane · **8** no row's cell names it · **64** usage — like every other read in this table, by A11 Addendum 4 ruling 1, which corrects act 0's `2` · **2** a helper predating the read | | `lanes-edit.sh last-session ` | the lane's resume target: the last uuid in the published cell **whatever shape it is in**, and failing that the session of its last `PAUSED`/`RESUMED`. This is what `/restart`'s step 4 reads, by A11 Addendum 4 ruling 14, rather than clause (f)'s `register-row` alone — so a lane whose row was never stamped but whose log records the session it paused in still has a resume target | | `lanes-edit.sh forks ` | the **live forks** of the lane's transcript — never holders, and a defect to retire | -| `lanes-edit.sh lanes [--repo\|--dir\|--prefix\|--ws\|--lane\|--here\|--all\|--closed\|--fetch]` | every lane, newest write first, tab-separated: clause (j)'s **ten columns in clause (j)'s order** — name, state, workstation, profile, window, last transcript uuid, directory, held objects, age, the line that binds it — then the read's own three, `home`, the count of live forks, and — since Amendment 18(b) — whether THIS place may pronounce on that binding (`here`, `elsewhere`, or `none` for a row with no binding line at all), which is what `lane-groups` files an `IDLE` row by — then Amendment 19's four: the row's **class** (`closed`, `dormant` or `none`), its `started` cell, its state cell's **head** and the **flag words** in that cell. The last two are carried **for a row with no object log** — 19(a)'s dormant row, whose cell is all this read has to show — and are `none` for a row that has one, which has its log instead: they are free text of up to 280 characters per row and the table the listing joins on is walked once per lane, so carrying them for every row cost the whole estate 3x (42 s against 14 on a register of 132 rows, measured). **No column is ever empty**, because three readers split the row with a tab-IFS `read`, to which an empty field between two tabs is no field at all. **CLOSED and DORMANT rows are left out unless `--closed` is passed** (19(b)); `--lane ` is never filtered, because its caller has named the lane. `lanes` and `lane` each render the subset their surface needs (A11 Addendum 4 ruling 7), and column 10 is the read's so the two cannot offer different commands; since Amendment 18 Addendum 2 the word it names is `lane `. **The one read whose default is local**, and `--lane ` answers about one without walking the estate. `--prefix ` is the LABEL fallback the checkout narrowing and `lane-start ` both ask for, used only where a lane has neither a home nor a `dir` | +| `lanes-edit.sh lanes [--repo\|--dir\|--prefix\|--ws\|--lane\|--here\|--all\|--closed\|--fetch]` | every lane, newest write first, tab-separated: clause (j)'s **ten columns in clause (j)'s order** — name, state, workstation, profile, window, last transcript uuid, directory, held objects, age, the line that binds it — then the read's own three, `home`, the count of live forks, and — since Amendment 18(b) — whether THIS place may pronounce on that binding (`here`, `elsewhere`, or `none` for a row with no binding line at all), which is what `lane-groups` files an `IDLE` row by — then Amendment 19's four: the row's **class** (`closed`, `dormant` or `none`), its `started` cell, its state cell's **head** and the **flag words** in that cell. The last two are carried **for a row with no object log** — 19(a)'s dormant row, whose cell is all this read has to show — and are `none` for a row that has one, which has its log instead: they are free text of up to 280 characters per row and the table the listing joins on is walked once per lane, so carrying them for every row cost the whole estate 3x (42 s against 14 on a register of 132 rows, measured). **No column is ever empty**, because three readers split the row with a tab-IFS `read`, to which an empty field between two tabs is no field at all. **Column 7, the directory, is escaped** the way `lane-worktrees`' porcelain escapes a field (#301): a backslash is written `\\`, a TAB `\t`, a newline `\n` and a carriage return `\r`, so a directory holding a TAB is still one column and the row still seventeen. `lanes`, `lane` and `worktrees` decode it before they show it or take it for a path, and a directory holding none of the four is printed as it is. **CLOSED and DORMANT rows are left out unless `--closed` is passed** (19(b)); `--lane ` is never filtered, because its caller has named the lane. `lanes` and `lane` each render the subset their surface needs (A11 Addendum 4 ruling 7), and column 10 is the read's so the two cannot offer different commands; since Amendment 18 Addendum 2 the word it names is `lane `. **The one read whose default is local**, and `--lane ` answers about one without walking the estate. `--prefix ` is the LABEL fallback the checkout narrowing and `lane-start ` both ask for, used only where a lane has neither a home nor a `dir` | | `lanes-edit.sh lane-groups []` | **the rows on STDIN**, each with the group the pick puts it in: `available` (PARKED, or a binding that workstation **and container** prove dead), `live`, `elsewhere` — an `IDLE` row whose binding is another container on this same host is **elsewhere**, because IDLE means this host saw no live record and across that seam the pid it would have read is in another namespace (Amendment 18(b)). Closed and dormant rows are DROPPED (Amendment 19). It reads nothing itself — the caller has already paid for `lanes`, and two surfaces computing one partition is how they come to disagree | | `lanes-edit.sh next-free ` | **the rows on STDIN plus every row of this checkout's register and of `lanes/archive/LANES-retired.md`** (Amendment 19(b) and (d): the rows the listing hides and the rows `archive-rows` has moved out still hold their positions), and the LOWEST position no lane of that repository HAS EVER held — `ENDED` and `RETIRED` rows reserve theirs, because a lane's identity is its name and its object log `lanes/log/.md` is append-only, so a second lane at a retired position would write its life into the first one's file. The name before the position is compared whole, so `repo-foo-1` is no lane of `repo`. `lanes`'s footer and `lane`'s `f` answer both read it, so the two cannot offer different positions | | `lanes-edit.sh binding ` | where the lane is bound, and whether this place may pronounce on it: ` ` (Amendment 18(b)). **0** bound · **8** free · **1** the log could not be read, which is never "this lane is free" |