Repository navigation
tests.yml: the full suite keeps its temporary files under runner.temp, not /tmp, so it runs on Ubuntu 26.04 and the tests job goes back to ubuntu-latest (#1096) - #1097
Conversation
…p`, not `/tmp`, and runs once on `ubuntu-26.04` by name to show it passes there (#1096) On the Ubuntu 26.04 that `ubuntu-latest` now gives out, the suite filled /tmp under pytest's default basetemp: #1092's run of the `tests` job (job 119050702775, image `ubuntu-26.04` 20261012.163.1) ended `2436 failed, 11382 passed, 380 skipped, 5579 errors`, with 28325 lines of `Disk quota exceeded` and then `No space left on device`, all under `/tmp/pytest-of-runner/pytest-0`. - The `tests` step passes `--basetemp="$RUNNER_TEMP/pytest"` and sets `TMPDIR` to `runner.temp` for everything it starts. `tests/conftest.py` already points `TMPDIR` at `<basetemp>/tmpdir` for the session, so the basetemp carries the suite's own temporary files with it; the step's `TMPDIR` holds what is written before the session starts and after it ends, such as pytest's capture files. `runner.temp` and not the workspace, which is this checkout: a test's folder there would sit inside this repository for every git that looks upward from it. - The step prints `df -hT /tmp "$RUNNER_TEMP"` before the suite and after it, and ends with the suite's own exit status. - `tests` runs on `ubuntu-26.04` by name for this pull request's proof run; it goes back to `ubuntu-latest` once the suite passes there. - tests/test_release_workflow.py: the `tests` job's 24.04 pin test is replaced by `test_the_suite_keeps_its_temporary_files_on_the_runners_disk`, which holds the step's `TMPDIR`, basetemp and exit status. - The `package` comment's sentence about `tests` says it asks for `3.x`, which 26.04 has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideThe PR addresses Ubuntu 26.04 disk exhaustion by placing pytest and process temporary files under the runner's dedicated temp directory, adds diagnostics and a fail-safe exit-status wrapper, runs the job on Ubuntu 26.04 for validation, and updates workflow regression tests to enforce the new configuration. File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
…ite passed on Ubuntu 26.04 with its temporary files under `runner.temp` (#1096) Round 1 of #1097 ran the job on `ubuntu-26.04` by name (job 119180581846, image `ubuntu-26.04` 20261018.168.1, Ubuntu 26.04.1 LTS). The `tests` step passed: `19388 passed, 392 skipped in 4120.87s (1:08:40)`. Its `df` lines show /tmp as a tmpfs of 7.9G, untouched (38M used before and after), and the runner's disk at 58G used before the suite and 83G after. The job itself failed only at actionlint 1.7.12, which does not know the label `ubuntu-26.04` ([runner-label]); `ubuntu-latest` it knows. - `tests` runs on `ubuntu-latest` again, and the proof run's comment is gone. The `tests` step's comment gives the measured sizes. - The `package` comment says that the other jobs keep their runners: `tests` asks for `3.x` and release.yml's `build` for `3.12` on ubuntu-latest, both of which 26.04 has, and `tests-git-bash` runs on windows-latest. - `setup_python_pairs()` and the allow-list test are unchanged, and hold `tests` to `3.x` or `3.12` on `ubuntu-latest` again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fetch that carry it run in bootstrap.py's `untraced()` environment, so `make siblings` and `family.py siblings` write the token to no trace the caller asks git for (#1055) (#1075) `make siblings` and `family.py siblings` now write the token in `SHAPE_LEGS_TOKEN` or `SHAPE_LEGS_APP_TOKEN` to no trace the caller asked git for. #996 (#1045) did the same for `make bootstrap`. Lane 5 found this in its independent review of #1045 (rv996, #1045 issuecomment-6288783192) and measured it in #1055. `templates/family-root/scripts/siblings.py` gives the credential's `-c url.https://x-access-token:<token>@github.com/.insteadOf=...` rewrite, in argv, to two gits: - the clone in `place`, for a member with no clone beside the holder; - the fetch in `place`, for a member whose clone is there. Both ran in the caller's own environment. So every trace2 target the caller named wrote the token in the `start` event of each, one line per member. `scrub` kept it out of the output, and only that part held. Now: - **`rewrite_environment(token)`**, a new function in `siblings.py`: - with a token in use, it returns `untraced()` from the `bootstrap.py` beside it. That is every `GIT_TRACE*` variable taken out, and `GIT_TRACE2`, `GIT_TRACE2_EVENT` and `GIT_TRACE2_PERF` set to `0`, which also turns off a target the global or the system config names; - with no token, it returns None, so the two gits keep the caller's environment and stay traced where the caller asked, as before. - **The clone and the fetch** each run with `env=rewrite_environment(token)`. Nothing else in the file changes environment. - **The member's own `scripts/bootstrap.py`**, which `place` runs after a clone, is given no token in its argv, and no `env`, so it keeps the caller's environment and its traces. That environment holds `SHAPE_LEGS_TOKEN` and `SHAPE_LEGS_APP_TOKEN` as before; the shipped member bootstrap (`templates/assembly-root/scripts/bootstrap.py`) reads neither. A test row holds this, and so does `tests/test_validator_child_encoding.py`, which reads that call as handing no `env`. - **#1023's jobserver handling is untouched**: `dispatch` still runs each member's make with `member_make_environment(make)`, and no `MAKEFLAGS` reading changed. - **The docstrings** now say the promise in full: `git_prefix` says the token is "never written into `.git/config`, never persisted, never printed, and never traced". `place`'s ABSENT paragraph in the module docstring says the same, and `rewrite_environment` says what was measured. **One thing the issue did not ask for.** `GIT_TRACE_PERFORMANCE` writes a git's whole command line, `-c` included, on git 2.43.0 and 2.47.1 alike. So at main it held the token too, two lines per run, and the rows below set it. `untraced()` already takes it out: every `GIT_TRACE*` variable goes. This follows #1045's `untraced()` (#996): the clone and the fetch run in the very environment `make bootstrap` gives every git it hands the token. `siblings.py` imports `untraced` from the `bootstrap.py` beside it, next to `REWRITE_TARGETS`, `credential`, `member_make_environment`, `member_path` and `members_of`. The issue left this to the writer, because a holder may keep a `bootstrap.py` older than its `siblings.py` (`update-shape.py apply --accept-local`), and an import of a name that copy lacks would stop `make siblings`, `park` and `resume` with an `ImportError`. The issue's text was written against main `1a47ed07`, where `siblings.py` still kept its own copy of the `MAKEFLAGS` readings. Since then #1023 (`9e154d87`, lane 4's) has decided the question for this pair of files: - it replaced that copy with an import of `member_make_environment`, because a copy in each script failed SonarCloud's duplication gate; - it named the price, in the import's comment and its commit: a holder that keeps its own `bootstrap.py` while `apply` writes `siblings.py` is refused, `update-accept-local-missing-name` (#536, #604), before a byte is written, and merges `bootstrap.py` by hand first. `untraced` takes the same road for the same reasons: - **One rule.** Which traces a command carrying the token is kept out of has one answer, for `make bootstrap` and `make siblings` alike. A copy here could drift from `bootstrap.py`'s, and the drift would be a token in a file. - **A kept old `bootstrap.py` is refused in the one-step case, and not in a two-step one.** The guard reads names. `untraced` is new with #996 (#1045), so a kept `bootstrap.py` from before it is refused by that name, where `--accept-local` names it in the same `apply`. Measured with `update-shape.py`'s own readers, in process: - `siblings.py` at this head takes `REWRITE_TARGETS`, `credential`, `member_make_environment`, `member_path`, `members_of` and `untraced` from `bootstrap`; - the holder's `bootstrap.py` at main `00f6d7f7` lacks none of them; - the holder's `bootstrap.py` at `6476c170` (main just before #1045) lacks `untraced` alone, which is the line the refusal names. - **The one-step case, measured end to end (rv1075).** A holder cut at `6476c170`, and `apply --at c3cf515 --accept-local scripts/bootstrap.py`: exit 2, `scripts/bootstrap.py (kept) lacks untraced, which scripts/siblings.py imports from it`, and the holder's files, HEAD and status unchanged. - **Two applies in a row are not refused (rv1075's SHOULD 1, filed as #1082).** A holder whose earlier apply kept a `bootstrap.py` without `untraced` (rv1075 applied `--at 00f6d7f --accept-local scripts/bootstrap.py`: that target's `siblings.py` imports no `untraced`, so there was nothing to refuse), and then an apply at this head without `--accept-local`, gets `siblings.py` copied. `scripts/siblings.py` then fails with `ImportError: cannot import name 'untraced' from 'bootstrap'`, and so do `make siblings`, `park` and `resume`. The cause is the guard in `update-shape.py` (`:4288-4289`): it checks only the files `--accept-local` names in the same run. That is the gap of #536's guard, and it is on main already for #1023's `member_make_environment`; this change puts `untraced` into it and does not widen it. The text above this paragraph said no `ImportError` could reach a holder, which was too strong; #1082 is the follow-up, and it is not done here. - **No copy, so no test to hold two copies to one answer.** `tests/test_update_shape_kept_helper.py`'s `test_what_siblings_takes_from_the_holders_bootstrap_is_found_defined` already holds that every name `siblings.py` takes is defined in the holder's `bootstrap.py`. Its docstring now says six names, not five. **Setup:** - git 2.43.0 (`/usr/bin/git`) and git 2.47.1, Python 3.12.3; - the family of `tests/test_family.py` (two members, local bare remotes, the file transport allowed through `GIT_CONFIG_COUNT`), laid out as `<tmp>/InkRouter/InkRouter`; - offline: a stub `gh` first on PATH, a bogus `GH_TOKEN`, an empty `GH_CONFIG_DIR`, `GIT_SSH_COMMAND=false`; - the holder's own `scripts/siblings.py` was main's (sha256 `86bf57e0...`) or this change's; - the fake token `w1055-a-token-no-forge-takes`. **Each case was run three ways:** - `make siblings`, which clones both members; - `make siblings` again, which fetches both; - `family.py siblings --family-root <holder>` in a fresh layout, which clones both. **Traces were asked for in one of three ways:** - the seven variables `GIT_TRACE`, `GIT_TRACE2`, `GIT_TRACE2_EVENT`, `GIT_TRACE2_PERF`, `GIT_TRACE_PACKET`, `GIT_TRACE_CURL` and `GIT_TRACE_PERFORMANCE`, each set to a file under the run's TMPDIR; - `trace2.eventTarget`, `normalTarget` and `perfTarget` in a scratch `GIT_CONFIG_GLOBAL`; - the same three in a scratch `GIT_CONFIG_SYSTEM`. Each way was run with `SHAPE_LEGS_TOKEN`, with `SHAPE_LEGS_APP_TOKEN`, and with no token. That is 108 runs at main and at the change, 54 for each git. Each run's TMPDIR and the whole family folder (the clones' `.git/config` included) were searched for the token. | traces asked by | main, a token set (both variables, both gits) | this change, a token set | no token, either | |---|---|---|---| | the seven variables | `trace2-event.json`, `trace2-normal.txt`, `trace2-perf.txt`, `trace-performance.txt`: 2 lines each, in the clone, the fetch and `family.py` alike | none | no token anywhere; the same files written | | the global config | `cfg-event.json`, `cfg-normal.txt`, `cfg-perf.txt`: 2 lines each | none | the same | | the system config | `sys-event.json`, `sys-normal.txt`, `sys-perf.txt`: 2 lines each | none | the same | **What the table rests on:** - Every one of the 108 runs (and the 54 runs again on this head's final bytes, sha256 `b1e7bb21...`) exited 0 and ended `siblings ok: 2 member(s) beside the holder in ...`, with the token in neither stdout nor stderr. - The 2 lines in each file are the `start` (or `performance:`) line of the git given the `-c`, one for each member. Each carries the token twice, once for each spelling the rewrite covers. - With every member a local path, `GIT_TRACE`'s file was written and held no token, and `GIT_TRACE_CURL` wrote nothing, with no http remote. An https member is a different case, measured below. - With the change and a token set: - every trace file but `GIT_TRACE_PACKET`'s was still written, by the run's other gits and the member's own bootstrap; - the packet trace was not written, since only the clone and the fetch write one here. **An https remote, measured offline (rv1075, then the row of Round 2).** The rewrite reaches only `github.com`, and the probes above are offline, with local paths. A member whose `.gitmodules` url is `https://github.com/<org>/<repo>.git` is reached by it, and can be tried offline behind a dead proxy, `http.proxy=http://127.0.0.1:9`, so that nothing leaves the host: - rv1075 set one member's url so, with `make siblings`, a fake `SHAPE_LEGS_TOKEN`, and the seven variables set to files, on git 2.43.0 and 2.47.1. Main's `siblings.py` (`86bf57e0`) held the token in `trace.txt`, `trace2-event.json`, `trace2-normal.txt`, `trace2-perf.txt` and `trace-performance.txt`; this head held it in no file and no output. The clone failed cleanly, `git clone exited 128`, and `make siblings` exited 2. - `GIT_TRACE`'s file holds it too, in the `run_command: git remote-https origin https://x-access-token:<token>@github.com/...` lines: 3 lines on git 2.43.0, 4 on 2.47.1 (rv1075). - Round 2 below holds this in a test row. **Still not measured:** a github.com clone or fetch that succeeds, since no run here reaches the network. `tests/test_family_siblings_untraced.py` is new. It uses `tests/test_family.py`'s `family` and `estate`, `offline` from `tests/test_family_add_refusals.py`, `files_holding` and `CREDENTIALS` from `tests/test_family_bootstrap_stops_named.py`, and `NO_CREDENTIAL` and `needs_make` from `tests/test_siblings_family_name.py`. No assert joins conditions with `and`. The token is the fake `w1055-a-token-no-forge-takes`. **The rows.** Each entry point is crossed with each way traces are asked for: - entry points: `make siblings` cloning, `make siblings` again fetching (after a first run with no token and no trace), and `family.py siblings` cloning; - ways: the seven variables, the three targets in a scratch global config (a copy of the session's, which keeps git's automatic maintenance off), and the three targets in a scratch system config. **Three tests** (the third is round 2's): - **`test_with_a_token_in_use_the_token_is_in_no_trace`**: 18 rows (3 entries x 3 ways x 2 variables). Each asserts: - exit 0 and `siblings ok: 2 member(s) ...`; - the token in neither stdout nor stderr; - the token in no file under the test's directory: TMPDIR, every trace and config file, and the clones and their `.git/config`; - every trace file the way asks for written: 5 for the variables, 3 for each config; - the member's own bootstrap traced where a member was cloned: a git traced in a leg of each clone, which only that bootstrap runs. Where nothing was cloned, nothing ran there. - **`test_with_no_token_the_clone_and_the_fetch_are_traced_as_asked`**: 9 controls (3 entries x 3 ways). Each asserts exit 0, `siblings ok` and the same trace files written. It also asserts the trace2 event file holds `siblings.py`'s own git at each member, read from the events: `git clone -q --no-local ...` to each member's slot, or `git fetch --quiet origin` in each member's clone. **Fails on main.** The file was run against main's `siblings.py` (sha256 `86bf57e0...`, put in place and then restored, sha256 checked): - **18 failed, 9 passed**: every row with a token failed, and the 9 controls passed; - the variables rows found the token in `trace-performance.txt`, `trace2-event.json`, `trace2-normal.txt` and `trace2-perf.txt`; - the global-config rows found it in `cfg-event.json`, `cfg-normal.txt` and `cfg-perf.txt`; - the system-config rows found it in `sys-event.json`, `sys-normal.txt` and `sys-perf.txt`. - **`test_an_https_member_with_a_token_in_use_is_in_no_trace`**: 3 rows, one for each of `CALLERS_CONFIG` (round 2 and round 3, below). Each mutant was applied alone to the worktree's file and the new test file run (git 2.43.0). The bytes were restored and checked by sha256 after each: - `siblings.py` sha256 `b776c69b...`: this head's code; it differs from the head only in two docstring lines; - `bootstrap.py` sha256 `50a16751...`, main's, unchanged here. All are **killed**. | mutant | result | |---|---| | M1 the token condition dropped: `untraced()`'s environment always | killed, 9 failed (every control) | | M1b the condition inverted | killed, 27 failed | | M1c the clone untraced always, the fetch as it is | killed, 6 failed (the clone controls) | | M2 the clone left in the caller's environment | killed, 12 failed (every clone row with a token) | | M3 the fetch left in the caller's environment | killed, 6 failed (every fetch row with a token) | | M4a `GIT_TRACE2_EVENT` not set to `0` (`TRACE2_OFF`) | killed, 12 failed (the global- and system-config rows) | | M4b `GIT_TRACE2` not set to `0` | killed, 12 failed (the same) | | M4c `GIT_TRACE2_PERF` not set to `0` | killed, 12 failed (the same) | | M5 the `GIT_TRACE*` removal dropped (`env = dict(os.environ)`) | killed, 6 failed (the variables rows, by `GIT_TRACE_PERFORMANCE`) | | M6 the prefix narrowed to `GIT_TRACE2` | killed, 6 failed (the same) | | M7 the member's own bootstrap run untraced too | killed, 12 failed (the clone rows' bootstrap check) | M5 and M6 are killed only because the variables rows set `GIT_TRACE_PERFORMANCE`. With a local-path remote, of the issue's six variables none but trace2's writes the `-c`, and trace2's three are set to `0` whatever the prefix does. With an https remote `GIT_TRACE` writes it too, in the `run_command: git remote-https` lines; that is what the row of Round 2 holds, and the mutant R4 below, which keeps the caller's `GIT_TRACE`, passed all 27 earlier rows. **How every run was made:** - through lane 5's runner: `/usr/bin/python3 -m pytest -q -rs -p no:cacheprovider -o tmp_path_retention_policy=failed`, one basetemp per run; - `LANES_*` cleared, a stub `gh` first on PATH, `GH_TOKEN=bogus`, an empty `GH_CONFIG_DIR`; - `EMAIL=service@opensoft.dev`, `GIT_SSH_COMMAND=false`, `GIT_CONFIG_GLOBAL=/dev/null` at the start of the session. | git | files | result | |---|---|---| | 2.43.0 | `test_family_siblings_untraced.py`, on this change before the docstring fix | 27 passed | | 2.43.0 | the same file against main's `siblings.py` | 18 failed, 9 passed | | 2.43.0 | gate shard A: 19 of the 41 files below | 1623 passed, 4 skipped, in 19:51 | | 2.43.0 | gate shard B: the other 22 of the 41 files | 2415 passed, 8 skipped, in 15:03 | | 2.47.1 | `test_family_siblings_untraced.py` | 27 passed, in 1:14 | **What the 41 gate files are:** - the new file; - `test_family_member_make_jobserver.py`; - every file `grep -l siblings tests/` names; - the pinned-copy and upgrade-row files: `test_pinned_copy_text.py`, `test_update_shape.py`, `test_update_shape_add.py`, `test_update_shape_kept_helper.py`, `test_no_auto_maintenance.py`, `test_template_text_placeholders.py`, `test_bootstrap_spelling.py`; - the trio: `test_repo_hygiene.py`, `test_agents_md_codes.py` and `test_cli_reference.py`. **The gate runs** (both shards at once, then the 2.47.1 run) were made on this change as it is committed: `siblings.py` sha256 `b1e7bb21...` and the new test file sha256 `7ba7a416...`, at main `00f6d7f7` (this branch's base; no rebase was needed, see Merges). The runner's `START` line read `dirty=2`, the two tracked files this commit changes, and a sha256 check after the runs found `siblings.py` unchanged (neither it nor the test files were modified after the runs started). The first pair of shards was stopped part way and re-run whole; only the re-runs count here. **The 41 files, by shard:** - shard A (19): `test_shape_doctor.py`, `test_validator_child_encoding.py`, `test_family_py_unreadable.py`, `test_pinned_copy_text.py`, `test_siblings_inputs.py`, `test_siblings_family_name.py`, `test_family_member_make_jobserver.py`, `test_update_shape_add.py`, `test_adopt_printed_sentences.py`, `test_family_printed_quoting.py`, `test_family_makefile_siblings.py`, `test_template_text_placeholders.py`, `test_park_resume_targets.py`, `test_windows_paths.py`, `test_doctor_gitmodules_not_utf8.py`, `test_local_remote_dir_urls.py`, `test_family_siblings_untraced.py`, `test_setup_family_folder.py`, `test_bootstrap_refusal_exit.py`; - shard B (22): `test_repo_hygiene.py`, `test_doctor_legs_members_next.py`, `test_update_shape.py`, `test_family.py`, `test_update_shape_kept_helper.py`, `test_yaml_reader_spaces.py`, `test_bootstrap_spelling.py`, `test_agents_md_codes.py`, `test_family_siblings_placement.py`, `test_no_auto_maintenance.py`, `test_cli_reference.py`, `test_family_siblings_bootstrap_unreadable.py`, `test_bootstrap_branch_bytes.py`, `test_family_init_asks_every_value.py`, `test_validate_workflow_gitmodules_urls.py`, `test_adopt_contracts_dir.py`, `test_doctor_unfinished_merge.py`, `test_family_members_not_a_list.py`, `test_family_init_landing.py`, `test_family_docs_one_spelling.py`, `test_doctor_members_spelled.py`, `test_pins_child_kind_and_siblings_root_spelling.py`. **The skips are the environment's, each named by its reason:** - shard A: 3 in `test_shape_doctor.py` (the PowerShell line is printed, and `powershell.exe` exists, only on a Windows host) and 1 in `test_family_member_make_jobserver.py` (`make -j2` here writes `--jobserver-auth=3,4`, not GNU make 4.4's named pipe); - shard B: 2 in `test_doctor_legs_members_next.py` (this git crashes on `submodule init`, exit 139, as git 2.43 does on a bare `branch`), 4 in the same file (this git dies on a `shallow` of -2**31, as git 2.43 does), and 2 in `test_no_auto_maintenance.py` (the session began with `GIT_CONFIG_GLOBAL` set, and its file includes that one); - the 2.47.1 run of the new file skipped none. The full suite was not run. **Static checks:** - flake8 finds in `siblings.py` only the three lines it finds at main (two E501, one E127, each moved down by the added lines); - in the new test file it finds only the F811s every fixture-importing file has; - both files are ASCII, apart from the dashes and the CJK example already in `siblings.py`. Fetched with `-c gc.auto=0 -c maintenance.auto=false`, on 2026-10-20 at about 21:03Z. Round 1, `git merge-tree --write-tree` of the first head `c3cf5154` against (round 2's are in its own section): - **origin/main `6c861635`**: clean, exit 0, tree `225b2a99`. - Main has moved two commits past this branch's base `00f6d7f7`: `9cbba9d5` (#1063: `scripts/family.py`, `scripts/shape_materialize.py`, `docs/cli.md` and two tests) and `6c861635` (#1065: `adopt-project.py` and three tests). - Neither touches `siblings.py`, `bootstrap.py`, `tests/test_update_shape_kept_helper.py` or the new test file, so there was no rebase and the gate runs above stand. - **#1062** (`fix/1040-windows-start-errors`, head `957ba038`), the one open PR that touches a family-root script this change reads (`templates/family-root/scripts/bootstrap.py`, with the assembly root's and `validate-family.py`, `validate-pins.py` and three tests): clean, exit 0, tree `84d4b54a`. - Its diff does not touch `untraced()`. - In the merged tree `bootstrap.py` still defines `untraced` (and the five other names `siblings.py` takes from it), and `siblings.py` is byte-identical to this head's (sha256 `b1e7bb21...`). - **The other 9 open PRs** (#1073, #1072, #1071, #1070, #1069, #1068, #1067, #1064, #1031): none touches `siblings.py`, `tests/test_update_shape_kept_helper.py`, or a file the new test imports from (`conftest.py`, `test_family.py`, `test_family_add_refusals.py`, `test_family_bootstrap_stops_named.py`, `test_siblings_family_name.py`), read from `gh pr list --state open --json number,headRefName,headRefOid,files`. `templates/family-root/scripts/siblings.py` is in `FAMILY_COPIED_VERBATIM`, so each holder gets one `upstream-changed` row for it, as #1045 gave one for `bootstrap.py`: - a holder that takes it with `bootstrap.py` from #1045 or later needs nothing more; - a holder that keeps an older `bootstrap.py` with `--accept-local` in the same apply is refused, `update-accept-local-missing-name`, naming `untraced`, before anything is written; - a holder whose earlier apply kept a `bootstrap.py` without `untraced`, and that then applies this change without `--accept-local`, is not refused: `siblings.py` is copied, and `make siblings`, `park` and `resume` meet an `ImportError`. That is the gap of #536's guard, which `member_make_environment` has on main already, and it is #1082's. No Windows or macOS run was made, since CI is Linux only (#597). rv1075, lane 5's independent reviewer, found `c3cf5154` READY (#1075 issuecomment-6302090874): no MUST, two SHOULDs and a NIT. One commit on top of it, `041f7831`, with no rebase: main has touched none of this PR's files. **The three findings:** - **SHOULD 1** (the body said no `ImportError` reaches a holder, and two applies in a row make one): answered in the body above, in "Where the helper comes from" and "The pinned copy". The gap is #536's guard's, it is on main for `member_make_environment` already, and it is #1082's; this PR does not change `update-shape.py`. - **SHOULD 2** (every row used a local file remote, so a leak through `GIT_TRACE` on an https member had no test, and rv1075's mutant R4 passed all 27 rows): answered by the new row below. - **NIT** (three places said the member's own bootstrap "is given no token"): `siblings.py`'s module docstring, `rewrite_environment`'s docstring and the test file's docstring now say it is given no token in its argv. It inherits `SHAPE_LEGS_TOKEN` and `SHAPE_LEGS_APP_TOKEN` in its environment, because `run_member_bootstrap` passes no `env`, and the shipped one reads neither. `rewrite_environment`'s docstring also names the https measurement. **The code of `siblings.py` is unchanged.** Its syntax tree with the docstrings taken out is the same at `c3cf5154` and at `041f7831` (compared with `ast`); the file's sha256 moved from `b1e7bb21...` to `19107ad4...` over comments and docstrings only. So round 1's two gate shards (1623 passed, 4 skipped; 2415 passed, 8 skipped) were not re-run; the targeted runs below are. **The new row,** `test_an_https_member_with_a_token_in_use_is_in_no_trace` (the file has 28 rows now). Its setup: - the estate of `tests/test_family.py`, with `IRRS`'s url in the holder's `.gitmodules` given as `https://github.com/InkRouter/IRRS.git`, and `IRSS` still a local path; - `http.proxy=http://127.0.0.1:9`, a dead proxy, in git's command scope after the entries the session holds, and `NO_PROXY` and `no_proxy` empty, so nothing leaves the host; - a fake `SHAPE_LEGS_TOKEN` and the seven trace variables set to files; - `make siblings`, cloning. It asserts: - the proxy is set where the row sets it: `http.proxy=http://127.0.0.1:9` is in the command scope the run's git reads (`command_scope_at`, which runs `git config --show-origin --list` and writes nothing); - exit 2 and `IRRS: git clone exited 128:` on stderr, which is how the head fails (rv1075 measured the same); - `IRSS` was cloned and `IRRS` was not; - the token is in neither stdout nor stderr, and in no file under the test's directory; - the five trace files the variables ask for are written, by the run's other gits. No assert names the proxy in git's message. The git 2.47.1 this lane builds has no `git-remote-https` (`git: 'remote-https' is not a git command`, `fatal: remote helper 'https' aborted session`), so there the clone fails at once without reaching the proxy, still with 128. `GIT_TRACE` has written the `run_command: git remote-https origin https://x-access-token:<token>@github.com/...` line before that, so the row finds the leak on both gits. A first local version asserted the proxy's message and failed on 2.47.1 for that reason; the assert was dropped, and the commit amended, before anything was pushed. **It fails on main.** The file was run against main's `siblings.py` (sha256 `86bf57e0...`, put in place and then restored, sha256 checked each time): - git 2.43.0, the whole file: **19 failed, 9 passed**, the 18 rows of round 1 and the new row. The new row fails at `assert files_holding(tmp_path, TOKEN) == []`, with 5 files holding the token: `temp/trace-performance.txt`, `temp/trace.txt`, `temp/trace2-event.json`, `temp/trace2-normal.txt` and `temp/trace2-perf.txt`. The round 1 rows find 4 of those, since a local path leaves `temp/trace.txt` clean; - git 2.47.1, the row alone: **1 failed**, the same 5 files. **It kills R4.** R4 is rv1075's mutant, in `rewrite_environment`: `return {**untraced(), **{k: v for k, v in os.environ.items() if k == "GIT_TRACE"}} if token else None`, which keeps the caller's `GIT_TRACE` for the clone and the fetch. Applied alone, then restored and sha256-checked: - git 2.43.0, the whole file: **1 failed, 27 passed**: the new row alone, with `temp/trace.txt` the one file holding the token; - git 2.47.1, the row alone: **1 failed**, the same one file. **The runs on the pushed head `041f7831`** (the runner's `START` line read `dirty=0`), through the same runner as round 1: | git | files | result | |---|---|---| | 2.43.0 | the new file, `test_update_shape_kept_helper.py`, `test_family_makefile_siblings.py`, `test_family_member_make_jobserver.py`, `test_pinned_copy_text.py`, and the trio (`test_repo_hygiene.py`, `test_agents_md_codes.py`, `test_cli_reference.py`) | 589 passed, 1 skipped (the jobserver file's named-pipe row, as in round 1), in 5:09 | | 2.47.1 (`git version 2.47.1`, printed from the exact path first on PATH) | the new file | 28 passed, in 2:13 | | 2.43.0 | the new file against main's `siblings.py` | 19 failed, 9 passed | | 2.47.1 | the new row against main's `siblings.py` | 1 failed | | 2.43.0 | the new file with R4 | 1 failed, 27 passed | | 2.47.1 | the new row with R4 | 1 failed | | 2.43.0 | on a predicted merge with main (below): the new file, `test_update_shape_kept_helper.py`, `test_pinned_copy_text.py`, `test_family_makefile_siblings.py` | 305 passed, in 2:50 | The full suite was not run. flake8 finds in `siblings.py` the same three lines as at round 1, and in the test file only F811s, from the fixtures it imports. Both files are ASCII, apart from the dashes and the CJK example already in `siblings.py`. **The merges of round 2.** Fetched with `-c gc.auto=0 -c maintenance.auto=false` at about 23:00Z; `git merge-tree --write-tree` of `041f7831` against: - **origin/main `c13c3985`** (#1076's squash, which touches `templates/family-root/scripts/bootstrap.py` and `tests/test_family_bootstrap_stops_named.py`, among others): clean, exit 0, tree `8ae10d0c`. None of the three files this PR changes is among the files main changed since the base `00f6d7f7`, so there is no rebase. In that tree `siblings.py` is byte-identical to this head's, `untraced()` has the same syntax tree as at the base, and `CREDENTIALS` and `files_holding`, which the new file imports from `test_family_bootstrap_stops_named.py`, are still defined. The 305-passed run above is on that tree; - **#1062** (`fix/1040-windows-start-errors`, head `957ba038`): clean, exit 0, tree `e6ed1ba2`. Its `untraced()` has the same syntax tree as main's; - **the other open PRs** (#1031, #1069, #1070, #1072, #1073, #1081, #1084): none touches `siblings.py`, `tests/test_update_shape_kept_helper.py`, `bootstrap.py`, or a file the new test imports from, read from `gh pr list --state open --json number,headRefName,headRefOid,files` at about 23:00Z. #1076 (`fix/1056-signal-anywhere`, head `73906948`) was open when the runs were made, and merged clean with this head then (tree `6ae3e65f`); it has landed since as `c13c3985`, above. **The failure.** Lane 5's landing gate (log `c1075.log`, #1075 issuecomment-6304830183) failed the https row of round 2 at `041f7831`: 1 failed, 356 passed. The change in `siblings.py` was not at fault; the row depended on the caller's git config. - The gate ran with neither `GIT_CONFIG_GLOBAL=/dev/null` nor `GIT_SSH_COMMAND=false`, which the writers' runs and round 2's runs had. - `conftest.py`'s session global file includes the caller's global config (or `~/.gitconfig`, where `GIT_CONFIG_GLOBAL` is unset). The operator's `~/.gitconfig` has `url.git@github.com:.insteadOf=https://github.com/`. - Git keeps the first of two `insteadOf` prefixes of the same length, and the config files are read before the command line, so that rewrite beat the token's `-c` rewrite of the same prefix. Measured with scratch files and a stand-in token, on git 2.43.0: under a global file with that rewrite, `git -c url.https://x-access-token:T@github.com/.insteadOf=https://github.com/ ls-remote --get-url https://github.com/InkRouter/IRRS.git` printed `git@github.com:InkRouter/IRRS.git`. - So the row's `https://github.com/InkRouter/IRRS.git` went over ssh to `InkRouter/IRRS`, a real private repository. The dead proxy never applied, the clone succeeded, `make siblings` exited 0 and the placed members were both there, and the row failed `assert result.returncode == 2`. **The fix** is in `tests/test_family_siblings_untraced.py` only. No other file changed in this round, and `siblings.py` is byte-identical to `041f7831`'s (sha256 `19107ad4...`). - **`hermetic_config`** gives the https row's git a global file of its own, `session_global_config("")` (`conftest.py`'s own function: automatic maintenance off, and no include of the caller's file), `GIT_CONFIG_NOSYSTEM=1` and `GIT_SSH_COMMAND=false`. - It is the least invasive way: only the one row with an https url sets it, `conftest.py` and every other row stay as they were, and the other rows' remotes are local paths, which no rewrite of GitHub's url reaches. - `GIT_CONFIG_GLOBAL` set takes git's two user-level files out of the reading, and `GIT_CONFIG_NOSYSTEM` the system file whatever `GIT_CONFIG_SYSTEM` says (checked on git 2.43.0 and 2.47.1 with scratch files). - `GIT_SSH_COMMAND=false` is a second wall: a url somehow sent over ssh runs `false`. No mutant can show it needed, since the runner exports it too. - **`url_after_config`** is a new assert before the clone: `git ls-remote --get-url <url>` (it applies the config's `insteadOf` and asks nothing of the network) must give the url unrewritten under the row's environment. A config that reaches the row now fails by name, before any clone. - **The row is parametrized by `CALLERS_CONFIG`**: `none` (round 2's row), and `global` and `system`, each a stand-in for a caller's config that would send the url somewhere reachable. `as_the_callers_config` writes a scratch file of the test's own, `url.<file URI of the family's own IRRS remote>.insteadOf=https://github.com/InkRouter/IRRS.git`, into this process's `GIT_CONFIG_GLOBAL` (the session file includes it) or `GIT_CONFIG_SYSTEM`. It is built from tmp files only: no network, and never the real `~/.gitconfig`. The file now has 30 rows. - With the fix, in each of the three, the clone fails at the proxy with git's 128, `make siblings` exits 2, `IRSS` is placed and `IRRS` is not, and the token is in no output and in no file under tmp_path. **The variants fail without the fix.** Each was applied alone to the worktree's test file (or `siblings.py`) and run through the runner, with the file's sha256 checked after it was restored: - **`041f7831`'s file as pushed, under a caller's global config.** Lane 5's runner now honours `L5_GIT_CONFIG_GLOBAL=<scratch file>` as the caller's global config, with ssh impossible. The scratch file rewrote `https://github.com/InkRouter/IRRS.git` to the run's own IRRS remote (a `file://` url under the run's basetemp). The whole file, git 2.43.0: **1 failed, 27 passed**, the https row at `assert 0 == 2`, the gate's failure reproduced with no network. - **T2, `041f7831`'s row plus the variants:** the new file with `hermetic_config` and the `url_after_config` assert taken out. The https rows, git 2.43.0: **2 failed, 1 passed**, `[global]` and `[system]` at `assert 0 == 2` (the clone went to the local remote and exited 0), and `[none]` passes. On git 2.47.1 the same. - **T1,** the row's global file dropped and the assert kept: `[global]` fails at the assert, which sees `file:///...IRRS.git` for the url; the other two pass. - **T3,** `GIT_CONFIG_NOSYSTEM` dropped and the assert kept: `[system]` fails at the assert; the other two pass. **R4 stays killed.** rv1075's R4 (`rewrite_environment` keeps the caller's `GIT_TRACE`), git 2.43.0, the whole file: **3 failed, 27 passed**, the three https rows. **The runs on the pushed head `962ae43c`** (`START` read `dirty=0`), through the same runner as before: | git | files | result | |---|---|---| | 2.43.0 | the new file, `test_update_shape_kept_helper.py`, and the trio (`test_repo_hygiene.py`, `test_agents_md_codes.py`, `test_cli_reference.py`) | 359 passed, in 3:05 | | 2.47.1 (`git version 2.47.1`, printed from the exact path first on PATH) | the new file | 30 passed, in 1:51 | | 2.43.0 | the new file, with `L5_GIT_CONFIG_GLOBAL` naming that scratch file | 30 passed, in 2:21 | | 2.43.0 | `041f7831`'s file, with the same | 1 failed, 27 passed | | 2.43.0 / 2.47.1 | T2, the https rows | 2 failed, 1 passed / 2 failed, 1 passed | | 2.43.0 | T1, T3, the https rows | 1 failed, 2 passed each | | 2.43.0 | R4, the whole file | 3 failed, 27 passed | The full suite was not run. flake8 finds in the test file only F811s from the fixtures it imports, and nothing over 79 columns; the file is ASCII. **The merge-tree of round 3.** Fetched with `-c gc.auto=0 -c maintenance.auto=false` at about 10:53Z; `git merge-tree --write-tree` of `962ae43c` against: - **origin/main `2a119f28`** (#1092): clean, exit 0, tree `b5ea0114`. Main has landed #1076 (`c13c3985`) and #1062 (`ff0c72eb`) since the last round, and has changed `templates/family-root/scripts/bootstrap.py` and `tests/test_family_bootstrap_stops_named.py` among others, but none of this PR's three files. In that tree `siblings.py` is byte-identical to this head's, `untraced()` has the same syntax tree as at the base `00f6d7f7`, and `CREDENTIALS` and `files_holding` are still defined where the new file imports them from. - **#1088** (`fix/1085-nit-texts`, head `88af1b7b`), which touches the same two files of main's: clean, exit 0, tree `365df092`, with the same findings. - **The other open PRs** (#1087, #1090, #1091, #1097): none touches `siblings.py`, `bootstrap.py`, `tests/test_update_shape_kept_helper.py` or a file the new test imports from, read from `gh pr list --state open --json number,headRefName,headRefOid,files` at about 10:53Z. Lane: openreposhape-5 (openRepoShape-5) Review: rv1075, lane 5's independent reviewer, not the writers (w1055 and f1055): READY at `c3cf5154` (issuecomment-6302090874) with no MUST; its two SHOULDs and its NIT were taken in one new commit, and the re-check is READY at `041f7831` (issuecomment-6303900180), with no MUST or SHOULD; its one NIT, a merge-tree number in the body, is fixed in the body. CI (Brett Heap's ruling 27): H0 is the head 962ae43 itself, which passed tests, tests-git-bash and SonarCloud; main has touched none of its files since its base 00f6d7f; and the local gate passed on its predicted squash tree fc2afb3 over main 16f9a0e: the family_siblings_untraced, update_shape_kept_helper, repo_hygiene, agents_md_codes, cli_reference sets, 359 passed. Landed on Brett Heap's word of 2026-10-18T14:45:28Z, relayed to every lane by lane 3 (#473 issuecomment-6251255596): "merge v1.2.0 PRs once reviewed and green". Closes #1055 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…` runs the suite on `ubuntu-latest` again, as it does once `tests` is back there (#1096) #1095 changed this sentence to `ubuntu-24.04` when it pinned the `tests` job there. This pull request moves the job back to `ubuntu-latest`, so the sentence follows it. Nothing else in the file changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-3, 2026-10-21T15:33:07Z) RV1097, independent review of #1097 at head 9ae7622: READY. MUST: none. SHOULD:
NIT (PR body only):
Checks:
Tests at the head (stub gh exit 97, GH_TOKEN=bogus, empty GH_CONFIG_DIR, GIT_SSH_COMMAND=false, GIT_CONFIG_GLOBAL=/dev/null, EMAIL set): test_release_workflow.py 59 passed; test_workflow_concurrency.py 14 passed; test_repo_hygiene.py 100 passed. Mutants (file restored, checked with cmp, git diff empty): T1 TMPDIR: /tmp KILLED; T2 --basetemp dropped KILLED; T3 exit "$status" dropped KILLED. Each one failed only test_the_suite_keeps_its_temporary_files_on_the_runners_disk (1 failed, 58 passed). Merges: merge-tree with origin/main 823624d is clean, tree 649e0d86bcd8. No other open PR touches .github/ or these test files. Not re-run: the doctor test file (the writer ran it at this head, 186 passed, 6 skipped), probes A-E and mutants 1-2 (run at ba1a232, and the head commit adds no line they test), and the full suite. Lane 3's plan: #1097 is READY at 9ae7622. S1 (the tests.yml comment cites round 3's job) and N1 to N3 (the body) go in one small fix round, made together with the update-branch that the landing after the v1.2.0 tag needs anyway, so they cost no extra CI round. RV1097 then checks that head. #1097 stays a draft with no milestone and lands after the v1.2.0 tag, on a later word. Lane: openreposhape-3 (openRepoShape-3) |
…263572144, which concluded success, and no longer cites job 119180581846 as a pass although its actionlint step failed (#1096) The comment said #1097's run on 26.04 (job 119180581846) passed. That job concluded failure: its actionlint step failed on the unknown `ubuntu-26.04` label, and only its `tests` step passed. It now cites round 3 (job 119263572144, `ubuntu-latest`, image ubuntu-26.04 20261012.163.1, the image #1092 failed on), whose `df` lines show /tmp at 38M used before and after and the runner's disk at 57G used before the suite and 83G after. Nothing but the comment changes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-3, 2026-10-21T21:07:07Z) RV1097 re-check of #1097 at head 9402c4d (main 038dafb, 21:03Z): READY against main, but landing needs a ruling on #1142 first. Fixed:
SHOULD (ruling):
NIT:
Round 4 (run 39632361496, job 119333706724): success; merge ref ff84540 (9402c4d into 4ed7c7b); image ubuntu-26.04 20261012.163.1; CPython 3.14.8; git 2.55.0; 19642 passed, 393 skipped in 1:39:26; df before: /tmp tmpfs 7.9G with 38M used, /dev/root 57G used and 88G free; df after: /tmp 38M, /dev/root 83G used and 62G free; actionlint 1.7.12 OK. package, tests-git-bash and SonarCloud are success on the head. Main's 24.04 push job 119283526361 took 1:38:41, so the run time is not a 26.04 cost. Body: draft, no milestone, closingIssuesReferences [1096], only closing keyword Closes #1096, ends Closes #1096 / Lane / robot, nothing above U+007F but the robot, no Sourcery block. The status line is accurate on CI but does not mention #1142. Tests at 9402c4d (stub gh exit 97, GH_TOKEN=bogus, empty GH_CONFIG_DIR, GIT_SSH_COMMAND=false, GIT_CONFIG_GLOBAL=/dev/null, EMAIL set): test_release_workflow.py 59 passed; test_workflow_concurrency.py 14 passed; test_repo_hygiene.py 100 passed. Merges: with origin/main 038dafb, clean, tree 53552f8085f5; main's two new commits touch none of .github/, the four test files, conftest.py or pyproject.toml. With #1142: conflict (S2). No other open PR touches these files. Not re-run: the mutants (the step lines and the test file are unchanged since 9ae7622, where T1 to T3 were killed), the doctor test file and the full suite. Lane 3's plan: #1142 is the operator's runner change for the GitHub-hosted billing cap, so #1142 lands first, and #1097 follows it, after the v1.2.0 tag as before. Lane 3 then merges main into this branch (a merge, no rebase and no force push), keeps Lane: openreposhape-3 (openRepoShape-3) |
…nt of the commit `--to` names, so a tag above it reads as one that reaches it and a tag below it keeps the plain words, and `--points-at` for `--contains` no longer survives (#1019) (#1107) No test held that a tag at a DESCENDANT of the refused commit counts as a tag that reaches it, so `--points-at` in place of `--contains` survived in `bump-leg.py` and `family.py` (mutant M9 of #988's review, filed as #1019). This adds the rows the issue asks for to the two reachability test files, and no production code changes. Opened as a draft with no milestone: Brett Heap's ruling of 2026-10-21T10:32:04Z ("leave the follow-ups out of v1.2.0") held it until the v1.2.0 tag, and it is now on the v1.2.1 milestone. Measured on main `2a119f28` before any change, and checked again on `16f9a0e81` and `7e00834c` (the tag questions did not change, only their line numbers): - `scripts/bump-leg.py` `_remote_tag_reaches` and `scripts/family.py` `_origin_tag_reaches` list the tags with `git for-each-ref --contains <commit> --format=%(objectname) refs/tags/`. No other copy of either exists (the `--contains` in `on_a_remote_branch` and `_on_a_remote_branch` asks about branches and is not this question). - The mutant (`--contains` -> `--points-at` on that one line in each script) SURVIVES every row on main: `test_bump_leg_reachability_words.py` 34 passed, `test_family_bump_reachability_words.py` 20 passed, 54 rows, as the issue says. - The production code is right: the new rows pass on unmutated main. So they do not "fail on main"; they fail on the mutant, which is the issue's own acceptance ("With `--points-at`, that row must fail"). No defect was found. `tests/test_bump_leg_reachability_words.py`: - `made_in_the_leg(project, name, on="HEAD")` takes an optional `on`, the commit the new commit is made on top of. Every existing call is unchanged. - `test_a_tag_at_a_descendant_of_the_commit_reaches_it`: a commit `made` and a child `above` on top of it, on no branch of the leg's remote. The leg and the remote each tag `above` (`v1-w1019`), made apart, in three kinds: both annotated (the reviewer's case J), leg lightweight and remote annotated, and the reverse. Both runs (dry run and real) refuse `made` `bump-leg-commit-local-only` in the TAG words, through `origin` and through `--local-remote-dir` (3 kinds x 2 routes = 6 rows), with nothing moved and the leg's own tag as it was. The premises say the tag names the child, that no tag is AT `made` (`for-each-ref --points-at`), and, through #1087's `only_a_tag_reaches`, that a tag of the remote reaches it, no branch does and no remote-tracking ref of the leg does. - `test_a_tag_at_an_ancestor_of_the_commit_alone_keeps_the_plain_words`: the control (x 2 routes). The commit named is the child, and the leg and the remote tag only its parent. The plain words stay, "a pin the rest of the world cannot fetch" included. `tests/test_family_bump_reachability_words.py`: - `made_on(holder, env, parent, name)`: a commit never pushed, made in the mount on top of `parent`, through `commit_in_mount` (which checks `parent` out first), so the holder stays clean. - `test_a_tag_at_a_descendant_of_the_commit_reaches_it`: the same three kinds (3 rows), both `bump --dry-run` and the real `bump` refuse `member-to-local-only` in the tag words, with nothing moved and the mount's own tag as it was. - `test_a_tag_at_an_ancestor_of_the_commit_alone_keeps_the_plain_words`: the control (1 row). No assert joins conditions with `and` or `or`; each premise is its own assert. No README, docs, AGENTS.md or handbook text names these tests or their row counts (grep), so none changes. | Mutant | Rows before (main's) | With these rows | | --- | --- | --- | | `--points-at` in `bump-leg.py` | survives: 34 of 34 pass | killed: 6 failed, 36 passed (all six descendant rows; the two controls pass, as they should) | | `--points-at` in `family.py` | survives: 20 of 20 pass | killed: 3 failed, 21 passed (all three descendant rows) | | `--merged` in `bump-leg.py` (extra: a check read the other way round) | survives: 34 of 34 pass | killed: 8 failed (6 descendant rows and both controls) | | `--merged` in `family.py` (extra) | survives: 20 of 20 pass | killed: 4 failed (3 descendant rows and the control) | The failure is the one the issue names: the plain words ("is reachable from no branch of ...") where the tag words ("and a tag of ... reaches it, but no branch ... does") are expected. Logs: `r-mut-points-at-bump.log`, `r-mut-points-at-family.log`, `r-mut-merged-bump.log`, `r-mut-merged-family.log` (and `mut-main-*.log` for the 34 and 20 on `2a119f28`). On the pushed head `01fcb259`: - git 2.43.0 (`/usr/bin/git`): the two test files, 66 passed (42 + 24; 34 + 20 before). - git 2.43.0: the trio `tests/test_repo_hygiene.py`, `tests/test_agents_md_codes.py`, `tests/test_cli_reference.py` and `tests/test_update_shape_kept_helper.py`, 329 passed. On `1201680f` (the same two files on top of `16f9a0e8`, before `7e00834c`, whose three files no row of mine touches or runs): - git 2.43.0: the trio alone, 170 passed; the two test files that import helpers from mine (`test_bump_leg_fetch_refspecs.py`, `test_family_bump_fetch_refspecs.py`), 102 passed; the two test files, 42 and 24 passed. - git 2.47.1 (`$Q/v115/w764/git247/bin/git` first on PATH, `git --version` printed `git version 2.47.1`): the two test files, 66 passed. No script changed, so no other test runs a changed script. - `git merge-tree --write-tree HEAD origin/main` against a re-fetched `origin/main` (`7e00834c`, which is also the merge base): exit 0, tree `3a852e87fcfda41766ece8c1771e47689c622ad6`, equal to this head's tree. Against `16f9a0e8` before the last rebase: exit 0 too. - Open PRs read with `gh pr list --repo opensoft/openRepoShape --state open --json number,headRefName,isDraft,files`: 8 (#1102, #1101, #1098, #1097, #1091, #1090, #1088, #1075). None touches `tests/test_bump_leg_reachability_words.py` or `tests/test_family_bump_reachability_words.py`, so there is no merge-tree to run against any of them. - **The NIT.** The docstrings of the two descendant rows said "Every row before this one tagged the commit itself, so ... survived all 54 of them". 54 counts the two files together (34 + 20), several earlier rows tag nothing (the no-`origin` and prune rows), and a count goes stale with the next row. - **The fix, docstrings only.** Each now says only what holds: "No row before this one tags a descendant of the commit: the tags in them are at the commit itself or below it, so `--points-at` in place of `--contains`, the mutant M9 of #988's review, survived every row of this file." No row, assert or helper changed. The 54 in "What still held on main" above is the two files together, as it says. - **One commit on top of `01fcb259`, a fast-forward push, no rebase:** head `ee48b5fe9693ebda099d1c0aadaca7bdc16b91c1`, read back with `git ls-remote`. Its tree is `615e571bb62fd1cf481e4152278b0e3628bab059`. - **Runs** (git 2.43.0, through `run9.sh`, `EMAIL=service@opensoft.dev`): `tests/test_bump_leg_reachability_words.py` 42 passed, `tests/test_family_bump_reachability_words.py` 24 passed. They ran on `7186f3cf`, the same tree as the pushed head; only the commit message was shortened after. - **Merge-tree** against a re-fetched `origin/main` (`6da757cb`, merge base `7e00834c`): exit 0, tree `453566df33c886cf7fc2b1c39af02acbbff365dc`. Main moved by nine files, none of mine; its `scripts/bump-leg.py` change (9 lines added) leaves `_remote_tag_reaches` and its `--contains` line alone (now line 1214). Review: rv1104-1107, lane 5's independent opus reviewer, which wrote none of #1107: READY at `ee48b5fe`, the head that lands (issuecomment-6318124100), with no MUST or SHOULD and one optional test NIT that needs no round. CI (Brett Heap's ruling 27): H0 is the head ee48b5f itself, which passed tests, tests-git-bash and SonarCloud; main has touched none of its files since its base 7e00834; and the local gate passed on its predicted squash tree 2f7f587 over main 422a590: the bump_leg_reachability_words, family_bump_reachability_words, repo_hygiene, agents_md_codes, cli_reference sets, 237 passed. Landed on Brett Heap's word of 2026-10-23T13:10:26Z, relayed to every lane by lane 3 (#473 issuecomment-6365697123): "merge v1.2.1 PRs once reviewed and green". Closes #1019 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s message spells a path byte that is not UTF-8 as `_shown` does, an escape, and no longer says it names it with a `?` in its place, which #900 replaced (#1018) (#1104) `env_commit`'s docstring in `scripts/shape_materialize.py` says what the split commit's message does with a `root` or `drop` path that holds a byte that is not UTF-8, as the code does since #900. It said the message names such a path "with a `?` in place of that byte, a path that does not exist". That was true before #900, and it is not true now. A reader of the docstring is told about a `caf?.md` the tool no longer writes. Found by lane 1's writer on #900 and filed as #1018. Lane 5 took it outside v1.2.0, under Brett Heap's ruling of 2026-10-21T10:32:04Z. Measured on main `2a119f281` and again on `16f9a0e81` (main after #1087), with a small script that calls: `adopt-project.py`'s own `_split_message` and `_shown`, then `env_commit` and a real `git commit`, read back with `cat -A`. - The issue's claim held: the docstring (about line 2103 when filed, line 2268 on `2a119f281`, line 2349 on this branch) still said the message names the byte with a `?`. - The code does not. `_shown("caf\udce9.md")` is `` `caf\udce9.md` ``, and the split message for a `root` and a `drop` entry named that holds no lone surrogate. Through `env_commit` and `git cat-file commit HEAD`, `cat -A`: ``` DROPPED (in no leg and no longer here):$ `caf\udce9.md`$ STAYS IN THE ASSEMBLY ROOT:$ README.md$ `caf\udce9.md`$ ``` - What stays true of `env_commit` itself: a message that holds the lone surrogate, handed to it directly, is still written as `?`. `cat -A` reads `Name: caf?.md$`. So the `errors="replace"` paragraph is kept, and what changes is who it describes. - #1087 (main `16f9a0e81`) changed `scripts/shape_materialize.py` by 128 lines, none of them in `env_commit`, `COMMIT_COMMAND` or the message, and changed nothing in `adopt-project.py` (0 diff lines). The rebase onto it was clean and the docstring needed no other change. One file, `env_commit`'s docstring, in two paragraphs: the `errors="replace"` paragraph (round 1, 11 lines added and 7 removed) and the sentence above it (round 2, below; 3 added and 2 removed). Together 14 added and 9 removed against main `6da757cb`. The `errors="replace"` paragraph now says: - encoding, a character UTF-8 cannot carry is written as `?`, and nothing raises after both legs are pushed, as before; - `adopt-project.py` refuses a lone surrogate in a path it extracts (`entry_path_problem`), and a `root` or `drop` entry that holds one is listed in the split message but never raw: the message names each path as `plan`'s report does (`_shown`, #900), so the byte 0xE9 reads as an escape with no surrogate in it, `` `caf\\udce9.md` ``, the path the source holds; - written raw it would be a `?`, `caf?.md`, a path that does not exist, which is what `env_commit` still writes for a lone surrogate it is handed. The backslash is doubled in the source, as the neighbouring docstrings write `\\udcc3`. A single `\u` in a non-raw docstring would be an escape that makes a lone surrogate. Measured: the docstring holds no character from U+D800 to U+DFFF and holds the six characters `\udce9`. The longest docstring line is 78 characters. **The code is unchanged.** A script compares the AST of `scripts/shape_materialize.py` with every docstring blanked: the branch's file is identical to `origin/main`'s after the rebase onto `16f9a0e81` (round 1), and the merge of this head into `origin/main` `6da757cb` is identical to `6da757cb`'s file (round 2). **No pin moves.** `scripts/shape_materialize.py` is not a pinned copy. `COPIED_VERBATIM`, `COPIED_FROM_SHAPE`, `FAMILY_COPIED_VERBATIM` and `FAMILY_COPIED_FROM_SHAPE` do not list it, and `templates/assembly-root/scripts/validate-pins.py` says of it "which no project carries". So no `upstream-changed` row, no digest, no assembly copy and no `tests/test_pinned_copy_text.py` entry changes. **No other text pins these words.** Searched in `tests/`, `README.md`, `docs/`, `docs/handbook.html`, `AGENTS.md` and `templates/`: no test reads `env_commit`'s docstring (`__doc__`, `getdoc`), and none of them holds "in place of that byte" or "a path that does not exist" for this. The other places that name the `?` are about this function's behaviour or about history, and are still true: `_split_message`'s docstring says `caf\\udce9.md` "was `caf?.md`" (before #900), `_refused_by_policy` already says the message "lists it as `_shown` does (#900)", and `tests/test_adopt_spelled_names.py` quotes the message as it was on `c7a3ff16`. The `?` in `argv_text`, `trailer_line` and the commit-trailer text is about a `--trailer`, not the split message. No rows and no mutants: the change is a docstring, the code is the same AST, and no test pins the docstring. So there is no row to fail on main and nothing to mutate. All with `$Q/v110/run9.sh`, `EMAIL=service@opensoft.dev`, `GIT_SSH_COMMAND=false`, `GIT_CONFIG_GLOBAL=/dev/null`, the stub `gh`, a fake token, git 2.43.0 (`/usr/bin/git`). Two shards, run before the rebase, at the `2a119f281` base with this one-file change in the tree. Together they are every `tests/*.py` that names `shape_materialize` or `env_commit` (86 files, including `tests/test_adopt_spelled_names.py` and `tests/test_adopt_entry_paths.py`, which run `env_commit` and the #900 message) and `tests/test_agents_md_codes.py`: | run | files | result | |---|---|---| | shard A | 43 | 2873 passed, 4 skipped in 1707.51s, rc=0 | | shard B | 44 | 4611 passed, 31 skipped in 2462.01s, rc=0 | After the rebase onto `16f9a0e81`, on the committed head `e32b2703d733f6c60c1b2cba2d62d164d93d7b9a` (`dirty=0`): the trio, `tests/test_repo_hygiene.py`, `tests/test_agents_md_codes.py` and `tests/test_cli_reference.py`, **170 passed in 55.67s**, rc=0. The docstring-only change needed no new shards: the shards' counts are runs at the `2a119f281` base, and #1087 did not touch `env_commit`. Round 2, on the committed head `de89aa81b1533e32f1007f991aeae05cd915b36d` (`dirty=0`): the same trio, **170 passed in 61.77s**, rc=0. The round 2 commit is one docstring sentence, so it needed no new shards either. git 2.47.1: no run. The change adds no test file of its own, so there is none to run on it. `git merge-tree --write-tree HEAD <other>` with HEAD at `de89aa81b1533e32f1007f991aeae05cd915b36d`, after a re-fetch of `origin main` with `-c gc.auto=0 -c maintenance.auto=false` (round 2, about 14:03Z on 2026-10-21): | against | result | |---|---| | `origin/main` `6da757cbe9a4eb66d60c34f38dcc2b332d175e8b` | clean, rc 0, tree `15c11b6c959fc4c7540105d5d62e3f961c8e27fd` | | #1105 `fix/1048-makefile-follow-up-gnu-read-order` `5a4de7f763b5a3c32adce9614a3a539508416eb4`, an open PR that touches `scripts/shape_materialize.py` | clean, rc 0, tree `db05aead67052643942e35a9689d9dd4a0873fda` | | #1118 `fix/1089-named-link-skip-tests` `c60066cbeec18b8b6c926e254ed4bee6b9a486c2`, the other open PR that touches `scripts/shape_materialize.py` | clean, rc 0, tree `a40df3b63c32c2a3d8f4c40587b094940c8d6567` | Read with `gh pr list --state open --json number,headRefName,headRefOid,files`: 16 open PRs, three of them (this one, #1105 and #1118) touch `scripts/shape_materialize.py`, the only file this change touches. The other 13 (#1120, #1119, #1117, #1111, #1109, #1107, #1106, #1102, #1101, #1098, #1097, #1091, #1088) touch no file this change touches. The same command with HEAD at the reviewed head `e32b2703` gives rv1104's trees: `de31d857` against `6da757cb` and `195ffe19` against #1105. The round 1 merge against #1090 is moot: #1090 has landed in `6da757cb`. Held as a draft until the v1.2.0 tag; it is now on the v1.2.1 milestone. - **NIT 1, `scripts/shape_materialize.py` lines 2340-2343, a line round 1 did not change.** The paragraph above the reworded one said the adoption's split message "names each entry path as the source spells it". Since #900 that is true of a printable path alone: `_split_message` lists any other through `_shown`, as the escape the next paragraph describes. It now says "as the source spells it (a printable one; see below)". One new commit on top of `e32b2703`, `de89aa81b1533e32f1007f991aeae05cd915b36d`, 3 lines added and 2 removed, docstring only, pushed as a fast-forward (no rebase, the PR is open). - Measured: the AST with docstrings blanked is identical to `e32b2703`'s and, merged into `6da757cb`, to `6da757cb`'s. The docstring holds no lone surrogate, still holds the six characters `\udce9`, and its longest line is 78 characters. - Searched `tests/`, `README.md`, `docs/`, the handbook mirror, `AGENTS.md`, `templates/` and the scripts for "names each entry path", "as the source spells" and the new words: only `tests/test_adopt_entry_paths.py` line 233 matches, a test's docstring about `execute` handing each path on as the source spells it, which is another sentence and pins nothing here. - **NIT 2, this body.** It named main as `16f9a0e81` and #1090 as the one open PR that touches the file. #1090 has landed. Main is `6da757cb`, and the merge-trees above are redone against it, against #1105 and against #1118, a draft that opened since and also touches the file. Review: rv1104-1107, lane 5's independent opus reviewer, which wrote none of #1104: READY at `de89aa81`, H0 of this landing (issuecomment-6318111413), with no finding; NIT 1 and NIT 2 of the round before are fixed. CI (Brett Heap's ruling 27 and his fast-refresh ruling of 2026-10-15T22:48:35Z): H0 de89aa8 passed tests, tests-git-bash and SonarCloud; the head 92285d4 is a clean update-branch merge of main b66d8f0, with tests-git-bash and SonarCloud green; and the local gate passed on its predicted squash tree 6bd2128 over main b66d8f0: the repo_hygiene, agents_md_codes, cli_reference sets, 171 passed. Landed on Brett Heap's word of 2026-10-23T13:10:26Z, relayed to every lane by lane 3 (#473 issuecomment-6365697123): "merge v1.2.1 PRs once reviewed and green". Closes #1018 Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Status: ready for review. The PR is still a draft; lane 3 marks it ready. The whole suite passed on Ubuntu 26.04 four times: in round 1, on
ubuntu-26.04by name, and in rounds 2 to 4, onubuntu-latest, which gave outubuntu-26.04each time (below). Round 4 ran on the final head9402c4d92, whose only change from round 3's head9ae7622d7is one comment intests.yml(RV1097's S1), and itstestsjob is green, as arepackage,tests-git-bashand SonarCloud.What changed
A follow-up outside v1.2.0 (Brett Heap, 2026-10-21T10:32:04Z). It lands only after the v1.2.0 tag, on a later merge word.
The problem (#1096): on the Ubuntu 26.04 that
ubuntu-latestnow gives out, the full suite filled/tmpunder pytest's default basetemp. #1092's run of thetestsjob (job 119050702775, imageubuntu-26.0420261012.163.1) ended2436 failed, 11382 passed, 380 skipped, 5579 errors, with 28325 lines ofDisk quota exceededand thenNo space left on device, all under/tmp/pytest-of-runner/pytest-0. #1095 moved the job toubuntu-24.04to keep it green.What round 1 measured: 26.04's
/tmpis a tmpfs of 7.9G, and the suite writes about 25G (the runner's disk went from 58G used to 83G over the suite). So the issue's inference holds: the suite cannot fit in 26.04's/tmp, and fits on the runner's disk with room to spare (62G still free after it)..github/workflows/tests.yml, thetestsstep):--basetemp="$RUNNER_TEMP/pytest", and the step setsTMPDIR: ${{ runner.temp }}for everything it starts.tests/conftest.py(temporary_directory, a session autouse fixture) already pointsTMPDIRandtempfile.tempdirat<basetemp>/tmpdirfor the whole session, andtests/test_adopt_temp_work_roots.pyholds it there. So moving the basetemp moves everything the tests and their children write while the session runs. The step's ownTMPDIRcovers what is written before that fixture and after it, such as pytest's capture files, whichtempfileopens at start-up.runner.tempand not the workspace: the workspace is this checkout, a git work tree. A basetemp inside it would put every test's repositories inside this repository, where any git that looks upward from a folder that is not a repository of its own finds this checkout instead.runner.temp(/home/runner/work/_temp) is outside the checkout and on the runner's disk. Its path is as long as the old one (/tmp/pytest-of-runner/pytest-0and/home/runner/work/_temp/pytestare both 30 characters), so no test meets a longer path than before.df -hT /tmp "$RUNNER_TEMP"before the suite and after it, so every run's log shows the room the suite had and used, and it still ends with the suite's own exit status./tmpintests/: none is written to. Every/tmpintests/*.pyandtests/conftest.pyis text that no test writes to: a--upload-pack=touch /tmp/pwnedthat is refused before it runs, a plan path--output=/tmp/pwnedthatexecuterefuses asplan-unsafe-path(tests/test_adopt_e2e.py:573), a spelling value"/tmp/x y/z"(tests/test_bootstrap_spelling.py:751), remote URLs whose names the doctor reads and never fetches,PurePosixPathvalues, a jobserver string, and a/tmp/claude-prefix that a hygiene test looks for.testsjob onruns-on: ubuntu-26.04by name (commitb3b8d5ad8).ubuntu-latest(commitba1a23204):testsruns onubuntu-latest, and both the proof run's comment and tests.yml and release.yml: the full suite and the Python 3.9 jobs run onubuntu-24.04, since the Ubuntu 26.04 thatubuntu-latestnow gives out has no 3.9 for setup-python and runs out of/tmpunder the suite (#1094) #1095's 24.04 pin comment are gone. Thepackagecomment says that the other jobs keep their runners:testsasks for3.xand release.yml'sbuildfor3.12on ubuntu-latest, both of which 26.04 has, andtests-git-bashruns on windows-latest.tests/test_release_workflow.py):test_the_tests_job_runs_the_suite_on_ubuntu_24_04is gone.test_the_suite_keeps_its_temporary_files_on_the_runners_diskholds the step'senvto{TMPDIR: ${{ runner.temp }}}and its commands to the five lines, among them the basetemp and the finalexit "$status". It sits after the allow-list test, so thepackagetest's docstring ("the next test holds every job of both workflows onubuntu-latest") is true again.setup_python_pairs()and the allow-list test are unchanged, and holdteststo3.xor3.12onubuntu-latestagain.9ae7622d7, added to this PR's scope by lane 3):tests/test_doctor_legs_members_next.py:37said "tests.ymlruns the suite on ubuntu-24.04 alone". It now saysubuntu-latest, which is true oncetestsis back there. Nothing else in the file changes.9402c4d92, the fix round for RV1097's S1): the comment intests.ymlsaid tests.yml: the full suite keeps its temporary files underrunner.temp, not/tmp, so it runs on Ubuntu 26.04 and thetestsjob goes back toubuntu-latest(#1096) #1097's run on 26.04 (job 119180581846) passed, but that job concluded failure: its actionlint step failed on the unknownubuntu-26.04label, and only itstestsstep passed. The comment now cites round 3 instead (job 119263572144,ubuntu-latest, imageubuntu-26.0420261012.163.1, the image shape-doctor.py: a leg's gitlink that no.gitmodulessection registers, beside one whose sections register other paths or beside none, is named with its own way out, as #914 names one beside a.gitmoduleswith no section (#1080) #1092 failed on):/tmpat 38M used before and after, and the runner's disk at 57G used before the suite and 83G after. Nothing but that comment changes.actions/setup-python@is also caught.Out of scope: nothing. #1096 has no "Needs a ruling" or "Documented limit" section.
CI rounds
b3b8d5ad8, run 39587689309,testsjob 119180581846, labelubuntu-26.04):ubuntu-26.04version 20261018.168.1, Ubuntu 26.04.1 LTS. setup-python's3.xgave Python 3.15.0.testsstep passed:19388 passed, 392 skipped in 4120.87s (1:08:40).dflines:/tmpis a tmpfs of 7.9G with 38M used, before the suite and after it./dev/root(ext4, 145G) had 58G used and 88G free before, and 83G used and 62G free after..github/workflows/tests.yml:69:14: label "ubuntu-26.04" is unknown ... [runner-label]. actionlint's list hasubuntu-latestandubuntu-24.04, so step 3'subuntu-latestclears it. This came from the proof run's own label, not from the runner, and it needed no fix of its own.package(24.04),tests-git-bashand SonarCloud passed.ba1a23204, run 39600385929,testsjob 119223091927, labelubuntu-latest):ubuntu-latestgave out imageubuntu-26.04version 20261018.168.1, Ubuntu 26.04.1 LTS.19419 passed, 392 skipped in 3961.03s (1:06:01). actionlint passed.dflines are the same as round 1's:/tmp, a 7.9G tmpfs, had 38M used before and after./dev/roothad 58G used and 88G free before, and 83G used and 62G free after.package(24.04),tests-git-bashand SonarCloud passed.9ae7622d7, the docstring commit on top of round 2's head; run 39612168967,testsjob 119263572144, labelubuntu-latest, 13:54:56Z to 15:21:51Z):4578d0cc, which is9ae7622d7merged into main6da757cbe, so main's newer tests are in its count.ubuntu-latestgave out imageubuntu-26.04version 20261012.163.1, the image shape-doctor.py: a leg's gitlink that no.gitmodulessection registers, beside one whose sections register other paths or beside none, is named with its own way out, as #914 names one beside a.gitmoduleswith no section (#1080) #1092's failing run had, and not round 1 and 2's 20261018.168.1. setup-python's3.xgave Python 3.14.8 this time, where rounds 1 and 2 had 3.15.0. git was 2.55.0.19574 passed, 393 skipped in 5111.69s (1:25:11). Thetestsstep ran 13:55:05Z to 15:20:19Z. actionlint 1.7.12 passed (stepsinstall actionlintandactionlintboth succeeded, no output).dflines:/tmp, a 7.9G tmpfs, had 38M used before and after./dev/root(ext4, 145G) had 57G used and 88G free before, and 83G used and 62G free after.package(24.04),tests-git-bashand SonarCloud passed.9402c4d92, the fix round's comment commit on top of round 3's head; run 39632361496,testsjob 119333706724, labelubuntu-latest, 16:10:20Z to 17:52:02Z):ff84540, which is9402c4d92merged into main4ed7c7bf5, so main's newer tests are in its count.ubuntu-latestgave out imageubuntu-26.04version 20261012.163.1, the image shape-doctor.py: a leg's gitlink that no.gitmodulessection registers, beside one whose sections register other paths or beside none, is named with its own way out, as #914 names one beside a.gitmoduleswith no section (#1080) #1092's failing run had, as in round 3. setup-python's3.xgave Python 3.14.8, and git was 2.55.0.19642 passed, 393 skipped in 5966.75s (1:39:26). Thetestsstep ran 16:10:29Z to 17:49:59Z. actionlint 1.7.12 passed (actionlint_1.7.12_linux_amd64.tar.gz: OK, stepsinstall actionlintandactionlintboth succeeded, no output).dflines:/tmp, a 7.9G tmpfs, had 38M used before and after./dev/root(ext4, 145G) had 57G used and 88G free before, and 83G used and 62G free after.package(24.04),tests-git-bashand SonarCloud passed.Tests, each file alone under a stub
gh(exit 97),GH_TOKEN=bogus, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=false,GIT_CONFIG_GLOBAL=/dev/null,EMAILset, one basetemp and-o tmp_path_retention_policy=failed.At head
9402c4d92(the comment commit; only a comment intests.ymlchanged from9ae7622d7):tests/test_release_workflow.py: 59 passedtests/test_workflow_concurrency.py: 14 passedtests/test_repo_hygiene.py: 100 passedAt head
9ae7622d7(the docstring commit):tests/test_doctor_legs_members_next.py: 186 passed, 6 skipped. pyflakes gives the same 207 warnings as atba1a23204.tests/test_release_workflow.py: 59 passedtests/test_repo_hygiene.py: 100 passedAt head
ba1a23204:tests/test_release_workflow.py: 59 passedtests/test_workflow_concurrency.py: 14 passedtests/test_install_sh.py: 399 passedtests/test_repo_hygiene.py: 100 passedtests/test_cli_reference.py: 23 passedpyflakes tests/test_release_workflow.py: no output, rc 0, as at origin/main.At
b3b8d5ad8, whosetestsstep is the same:tests/test_adopt_temp_work_roots.py, which holds the session'sTMPDIRto<basetemp>/tmpdir: 9 passed.TMPDIRandRUNNER_TEMPat one empty folder,--basetempat<that folder>/pytest): 9 passed, and afterwards the folder held onlypytest.Probes and mutants, at head
ba1a23204, each againsttests/test_release_workflow.py. After each one, the file was restored fromgit show HEAD:and checked withcmp, andgit statuswas clean.#1095's probes and mutants:
python-version: 3.9ontests: the allow list fails on('tests.yml', 'tests', 'ubuntu-latest', '3.9')(1 failed, 58 passed). Now thattestsis back onubuntu-latest, the allow list catches this alone, as it did before tests.yml and release.yml: the full suite and the Python 3.9 jobs run onubuntu-24.04, since the Ubuntu 26.04 thatubuntu-latestnow gives out has no 3.9 for setup-python and runs out of/tmpunder the suite (#1094) #1095's round 3.buildasks for'3.9': the allow list fails on('release.yml', 'build', 'ubuntu-latest', '3.9')(1 failed, 58 passed).testson a standard matrix (os: [ubuntu-latest],python: ['3.9']): the helper's assertion fails with('tests.yml', 'tests', ['os', 'python'])(1 failed, 58 passed).includerow withosand nopython: the${{check fails on('tests.yml', 'tests', 'ubuntu-latest', '${{ matrix.python }}')(1 failed, 58 passed).includerow{os: ubuntu-latest, python: '3.9'}: the allow list fails on('tests.yml', 'tests', 'ubuntu-latest', '3.9')(1 failed, 58 passed).ubuntu-latest: the install-check test and the allow list fail (2 failed, 57 passed).packageback onubuntu-latest: thepackagetest and the allow list fail (2 failed, 57 passed).New mutants for this PR's lines. Each one fails
test_the_suite_keeps_its_temporary_files_on_the_runners_disk(1 failed, 58 passed):TMPDIRset to/tmp.--basetemp="$RUNNER_TEMP/pytest"dropped.exit "$status"dropped, which would let the step pass over a failed suite.T1 to T3 also failed the same way at
b3b8d5ad8.Merges
git merge-tree --write-treeof head9402c4d92with origin/main4ed7c7bf5(read at 16:11Z, after the fix round's push): clean, rc 0, tree971dcb7b62ad. Main's one commit since823624d93changes none of.github/,tests/test_release_workflow.py,tests/test_doctor_legs_members_next.py,tests/test_workflow_concurrency.py,tests/test_repo_hygiene.py,tests/conftest.pyorpyproject.toml. The branch has not been merged with main or rebased: the landing after the v1.2.0 tag updates it.git merge-tree --write-treeof head9ae7622d7with origin/main823624d93(read after round 3 ended): clean, rc 0, tree649e0d86bcd8. Main's move from6da757cbeto823624d93changes none of.github/,tests/test_release_workflow.py,tests/test_doctor_legs_members_next.py,tests/conftest.pyorpyproject.toml.9ae7622d7with origin/main6da757cbe: clean, rc 0, tree7cac4bb9b4dd.ba1a23204with16f9a0e81was clean (tree2854a6a6590c).b3b8d5ad8with2a119f281and with16f9a0e81was clean.update-accept-local-missing-nameasks a copy an earlier apply kept, readunchanged, as a module a written copy imports from and as an importer of a written one, so a plain apply that stops either on its import is refused (#1082) #1133, bump-leg.py: a tag a leg with nooriginholds without its commit, or through a tag it lacks, is told so, a tag of a tree or a blob it lacks is refused by name, and rows holdYAML_NOT_TEXT_RE's exponents of two digits (#1103) #1131, scaffold-project.py: a push ssh refused the host's key for names how to check that key against GitHub's fingerprints, not the ruleset hint, and the hint on GitHub says what its re-run can still wait at (#1108) #1130, repo_shape.py and bootstrap.py:COMMIT_RE,SHA256_REandCOMMIT_40end in\Z, not$, so a pin'scommit:ortree_sha256:that ends in a line break is refused as not 40 or 64 hex by every validator andadopt-project.py(#1017) #1126, adopt-project.py:checkandexecuteask a plan'sorg:andid:right after its three repository names, so a bad one beside an unanswered entry, a moved source, a refused name or another repository is that one refusal in both, and apins:entry that is no pin is said as_read_assays it (#1020) #1125, validate-family.py:gitmodules-path-twiceand the check for values git dies on read the.gitmodulesgit reads, the index's where the work tree's is gone, and every section's lines endgit add -- .gitmodules, so a plaingit commitafter them takes the section out of HEAD (#1077) #1124, README.md, adopt-project.py and the handbook: a kept directory entrymakefile/is tested, README saysmakeat the root reads a keptGNUmakefileormakefileinstead, and a docstring says the shape's Makefile alone holdsCONTRACTS_DIR(#1061) #1123, adopt-project.py: anorg/repo--sourcetoo long for the disk is refused as a path is, naming no GitHub repository and offering no url, so--source <300 a's>/Thingis no longer offeredhttps://github.com/<300 a's>/Thing, which can never clone (#1003) #1122, adopt-project.py:execute's NEXT printspython3 scripts/bootstrap.pywhere GNU make at the root reads a keptGNUmakefileormakefile, and its NOTE names that file and what it takes formake bootstrapto run there (#1047) #1121, adopt-project.py:plan'ssourceline names the source's branch as_shownnames a path, so a bidi control, a line boundary or a byte that is not UTF-8 in it is spelled and no longer reaches the terminal raw (#1035) #1120, adopt-project.py: check asks the split's own clone of the source in the work directory, so a clone this git will not make is adopt-git-unasked before any leg, and _resolved and _answers make their repositories as check's other throwaways do (#1083) #1119, adopt-project.py, shape_materialize.py and tests: a named bad link left out of the copy and pin findings takes no other path's finding with it, and the docstrings and the materializer's refusal name the #979 exception and what helps it (#1089) #1118, family.py: theremovethat bothmember-duplicate-idremedies name and theaddthatbump'smember-unknownnames carry--family-root <holder>, quoted for the host, so each runs as printed (#1005) #1117, tests/test_path_guard_hygiene.py and shape-doctor.py: a bare is_file/is_dir/exists guard in a shipped tool fails by file and line unless its_is_aor a reasoned allowlist covers it, and aproject.yamllinked into an unsearchable folder isyaml-unreadable(#430) #1111, shape-doctor.py: a gitlink beside a.gitmodulesthe leg's index tracks and this disk lacks is named from the index's copy, which git reads, with its own way out that restores the file first (git restore .gitmodules), as #1080 names one beside other sections (#1093) #1109, tests: the bump-leg.py and family.py reachability rows tag a descendant of the commit--tonames, so a tag above it reads as one that reaches it and a tag below it keeps the plain words, and--points-atfor--containsno longer survives (#1019) #1107, adopt-project.py: under a one-byte locale such as Latin-1,checkreads a plan written in UTF-8 whose source is there, asking the plan's UTF-8 bytes where the spelling as written names nothing, rather than refusingplan-source-gone(#1078) #1106, shape_materialize.py and the pinned AGENTS-shape.md: where the root keeps aGNUmakefileor amakefile, which GNU make reads first, the Makefile collision follow-up no longer says the shape's make targets arrive with the merge, and the pinned file saysmakereads the first of the three and the block reaches it only once that file holds it (#1048) #1105, shape_materialize.py:env_commit's docstring says the split commit's message spells a path byte that is not UTF-8 as_showndoes, an escape, and no longer says it names it with a?in its place, which #900 replaced (#1018) #1104, family.py: a failed remove's by-hand lines spell a leg mounted at a path that is not UTF-8 as a printf word of octal escapes ending in a slash, sogit -C <member>/<leg>andsubmodule update -- <leg>typed in any POSIX shell name that leg (#1086) #1098, tests.yml: the full suite keeps its temporary files underrunner.temp, not/tmp, so it runs on Ubuntu 26.04 and thetestsjob goes back toubuntu-latest(#1096) #1097 and the family root's bootstrap.py:credential_adviceandended_onsay a member's failed clone ends git's update with 1 before any checkout but a leg's lets it go on, andkilled_saidsays git's update was itself killed, not that it went on (#1085) #1088): none but this one touches.github/,tests/conftest.py,tests/test_release_workflow.py,tests/test_workflow_concurrency.py,tests/test_repo_hygiene.py,tests/test_doctor_legs_members_next.pyorpyproject.toml.Closes #1096
Lane: openreposhape-3 (openRepoShape-3)
🤖 Generated with Claude Code