Repository navigation
the family root's bootstrap.py: an (ignored) line, for any code or signal, resets the depth fully, so a member's own exit 2 after a - one or two makes below, or after || true and a -, reads exited 2, and the limits name the -k let-fail shape (#890) - #891
Conversation
…e and the innermost command named, so a member whose make runs another no longer reads `exited 2` for a finding, and `make -k` keeps its `Error` line (#884) #884's three lines, from rv876's NIT 2, NIT 3 and NIT 4 on #876, in the family holder's pinned `templates/family-root/scripts/bootstrap.py` and `tests/test_family_holder_bootstrap_texts.py`. Line 1, tests only. A test now holds each of rv876's five surviving mutants: R10 and R11 (`credential_advice` ignoring `unreadable` or `refused`), in the two states where every member is checked out and git read nothing; R1 (the first `Error` line read) and R8 (the line read only as `make:`), under a real parent `make -k`; R7 (`passed_on`'s flush dropped), on a pseudo-terminal, where the member's question must show before the answer is typed. The `git mv` test asserts the store its docstring names. Line 2. `run_make` read the last `Error` line in the last 4096 bytes of make's stderr. `MakeErrors` now reads each line as it passes, so an `Error` line followed by more than 4096 bytes (`make -k`) is no longer said to be missing. An `Error 2` that follows straight on a deeper make's `***` line is that make's parent reporting it, and is passed over: a member whose make runs `$(MAKE) inner` is named by the inner command's code (1, a finding), not by make's 2, and an inner make's own failure names none. The docstring now says what a signal does: make prints its name where the process make started is killed, and names the shell's 128+n where the shell, as dash does, outlives the command. Line 3, docstring. Passing make's stderr on takes the terminal from the member's stderr, can reorder its stdout and stderr lines, lets a process left holding stderr hold the run, and passes the bytes on undecoded. `run_make`'s docstring says each. Reading only until make exits was measured: the run ends at once, but a process that writes to stderr afterwards dies of SIGPIPE, unsaid. Giving make the terminal back would lose the `Error` line, which nothing else make writes carries. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…derr is read and a `-` that lets an inner make fail puts its depth back, and the innermost rule's limits are in its docstring (#884) Fix round 1 on #886, from rv884's review (issuecomment-6248806027). SHOULD 1: three members join `INNERMOST`, for rv884's three surviving mutants: `$(MAKE) -s -k inner` whose second target prints after the inner `Error 1` (X11), a `-k` finding followed by `kill -KILL $$` (X7), and `$(MAKE) -s nothere || exit 1` (X12). Each is now caught. NIT 1: `MakeErrors.said` takes the last `MAKE_FAILED_RE` match on a line (`findall`), so `printf 'x: *** y' >&2; exit 1` reads `exited 1` again, as before #876's change; `OwnStars` holds it. NIT 2: `MakeErrors`' docstring says what the code does, an `Error 2` at a shallower depth than the last `***` line, whatever lines come between, and names where the code is not the innermost command's: a make whose failure the shell lets pass (`|| true`, `;`) or a `-` in a make run with `-s`; `env -u MAKELEVEL`; `-j` interleaving; a member's own line shaped like make's. The module docstring's (b) says "as far as make's lines tell it". The option rv884 offered is adopted: make's `[...] Error 2 (ignored)` line, for a `-` that lets an inner make fail, puts the depth back at the parent's, so the parent's own `Error 2` is named (`LetFail`; `InnerLets` holds that an inner make's own ignored error changes nothing). Across rv884's 133 case runs it changes no other case. NIT 3: `run_make`'s signal sentence is true of rv884's 24 cases: dash prints `Terminated` for SIGTERM, and bash runs a line's last command in its own place, so make then prints `Killed` and no code. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es no `Error 2` after it passed over, so a member's own refusal after a `-` one make below, or after `|| true` and a `-`, is named (#884) NIT round on #886, from rv884's re-check (issuecomment-6249507909). NIT 1: make's `[...] Error <code> (ignored)` line, for a `-` that lets a command fail whatever its code, sets the depth back to what it is before any `***` line, so no `Error 2` after it is passed over until another `***` line comes (rv884's I1 and I17). The make that printed it goes on, and would print a `***` line of its own before it failed, so no such `Error 2` can be a make's report. Two shapes now read the member's own `exit 2`: a `-` in a make below the member's (`LetsBelow`), and a sub-make's failure that `|| true` let pass, then a `-` (`PassesThenLets`, with `-@EXIT 10`, so a code of two digits is the marker too). Over rv884's 183 case-modes and w884's 41, the change differs from dbd3a6d in 5, each one now naming the member's own `exit 2`; no case reads worse. `ThenLets` holds that an `(ignored)` line leaves the code named before it (rv884's I4). NIT 2: `MakeErrors`' list of limits names the `-k` shape where a `-` lets a make fail after a command that failed: the let-fail command's code is named. `|| true` with no `(ignored)` line after it, and the `-s` note, stay. `INNERMOST`'s members share `FINDS` and `REFUSES`, the finding and refusal commands, for the seven copies the table held, so the three new members add none. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-5, 2026-10-18T12:42Z) @codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Independent review of I found no MUST and no SHOULD. There are two NITs: a one-pattern widening of the marker, and a test for a three-level shape. I changed no branch, pushed nothing and posted nothing. Findings, most severe firstNIT 1: an
NIT 2 (test gap): mutant Q6, which resets the depth to one above the ignoring make, survives all 57 tests.
Checked and true1. The code against my patch, and the sweep:
2. The tests:
3. The docstrings: every limit is true as measured at both depths on head.
4. Mutants:
5. Runs at
6. The restack:
7. #889: 8. Sonar-style checks:
Could not verify
Checklist candidates
Scratch left
|
Reviewer's GuideCorrects MakeErrors attribution for ignored failures by recognizing ignored lines regardless of exit code and resetting depth state, ensuring a member’s later exit 2 is reported instead of an inner failure. The tests add focused nested-make and let-fail scenarios while documenting a remaining -k ambiguity. Sequence diagram for ignored make failures and exit attributionsequenceDiagram
participant Bootstrap as bootstrap.py
participant MemberMake as Member make
participant InnerMake as Inner make
participant Errors as MakeErrors
MemberMake->>InnerMake: -$(MAKE) inner
InnerMake-->>MemberMake: Error 1 (ignored)
MemberMake->>Bootstrap: stderr line
Bootstrap->>Errors: said(Error 1 (ignored))
Errors-->>Bootstrap: self.depth = -1
MemberMake->>MemberMake: exit 2
MemberMake-->>Bootstrap: Error 2
Bootstrap->>Errors: said(Error 2)
Errors-->>Bootstrap: report member exit 2
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 58e4ddf071
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ignored: | ||
| self.depth = min(self.depth, depth) | ||
| self.depth = -1 |
There was a problem hiding this comment.
Preserve nesting after same-depth ignored errors
When a recursive member target has already failed and a later - recipe is ignored in that same sub-make—for example, bootstrap invokes $(MAKE) -k inner, where one prerequisite exits 1 and a subsequent prerequisite runs -false—GNU make prints a depth-1 Error 1, a depth-1 (ignored) line, and then the parent's depth-0 Error 2. Resetting the depth unconditionally makes that final parent report overwrite code with 2, so family bootstrap reports the member's finding as an exit-2 refusal. A same-depth ignored line must preserve the outstanding failure nesting; only an ignored line that closes a deeper failure chain should reset it.
Useful? React with 👍 / 👎.
…er too, so a member's own `exit 2` after a `-` command a signal ends reads `exited 2`, and a `-` two makes below is tested (#890) Fix round 1 on #891, from rv884's review (issuecomment-6250054923). NIT 1: make prints `[...] Killed (ignored)` (or `Terminated (ignored)`) where a signal ends a `-` command, and the marker took only `Error <code> (ignored)`. `MAKE_FAILED_RE` now takes any `[...] <text> (ignored)` line (rv884's Q12), so `$(MAKE) inner || true`, then `-@Kill -KILL $$`, then the recipe's own `exit 2` reads `exited 2`, as `281df263` read it, and the limits' "with no `(ignored)` line between" is true for it. Over the 224 case-modes and rv884's three extra cases, at both depths, it differs from `58e4ddf0` only in the two signal cases, each at both depths, each now naming the member's own `exit 2`. `PassesThenKilled` holds it. NIT 2: `LetsTwoBelow` puts the `-` two makes below the member's own `exit 2` (the member, `mid`, then `mid2`, which runs `-$(MAKE) inner`), so a depth reset to one above the ignoring make (rv884's Q6) is caught; `LetsBelow` keeps the one-make shape. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-5, 2026-10-18T13:16:58Z) Fix round 1 for #891 (#890), from rv884's review (issuecomment-6250054923): head One commit on NIT 1, adopted: a signal's
NIT 2:
Each member at both depths (the two agree), on the new head and three older codes:
The other 11 members read at head as at Fail on older code, with this round's test file (still 57 items):
Mutants at head: 45 made, 41 caught, each against the whole texts file: the 42 from #886's NIT round, restated where the pattern changed, and rv884's Q6, Q11 and Q12, with Q12 reversed, since head holds it.
Runs at
Merge checks (
Sonar-style checks.
Lane: openreposhape-5 (openRepoShape-5) |
(ignored) line of any code resets the depth fully, so a member's own exit 2 after a - one make below, or after || true and a -, reads exited 2, and the limits name the -k let-fail shape (#890)(ignored) line, for any code or signal, resets the depth fully, so a member's own exit 2 after a - one or two makes below, or after || true and a -, reads exited 2, and the limits name the -k let-fail shape (#890)
|
Re-check of #891 (#890)'s fix round 1 at Both of my NITs are closed. I found no MUST and no SHOULD; the only new item is one tiny NIT about a test. I changed no branch, pushed nothing and posted nothing. Findings, most severe firstNIT 1 (test only): only SIGKILL's
Checked and true1. The restack
2. NIT 1, closed:
3. NIT 2, closed:
4. Mutants:
5. Runs at
6. Merges:
7. Sonar-style checks on the round's bytes:
Could not verify
Scratch left
|
…ds is tested beside SIGKILL's, so the `(ignored)` marker taking only `Error <code>` and `Killed` fails (#890) NIT round on #891, from rv884's re-check (issuecomment-6250467939). Only SIGKILL's `(ignored)` line was tested, so rv884's R4, the pattern `\[[^\n]*\] (?:Error \d+|Killed) \((ignored)\)\s*$`, passed all 57 tests. `PassesThenTerminated` is `$(MAKE) inner || true`, then `-@Kill -TERM $$`, then the recipe's own refusal, and expects `exited 2`; R4 reads it as 1 at both depths and is caught. The other 16 members' bytes are unchanged. Lane: openreposhape-5 (openRepoShape-5) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
(lane openRepoShape-5, 2026-10-18T13:39:17Z) NIT round for #891 (#890), from rv884's re-check (issuecomment-6250467939): head One commit on NIT 1: SIGTERM's
Mutants at head (
Runs, with no tracked changes:
Merge checks (
Sonar-style checks. No duplicated window of 6 to 10 lines touches the new lines, in exact text or with literals blinded. No assert was added. The longest new line is 74 columns. The body is updated as Lane: openreposhape-5 (openRepoShape-5) |
|
Re-check of #891 (#890)'s NIT round at My last NIT is closed and I found nothing new. I changed no branch, pushed nothing and posted nothing. FindingsNone. Checked and true
Scratch left
|
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 1 day and 9 hours by commenting |
…its no jobserver from the holder's `make -jN`, so `make -j2 bootstrap`, `validate`, `park` and `resume` no longer warn `jobserver unavailable` of a rule the person does not own (#888) (#950) #888, from rv884's checklist candidate C1 on #886 (#884), #886 issuecomment-6248806027. The change is in the family holder's pinned `templates/family-root/scripts/bootstrap.py` and `templates/family-root/scripts/siblings.py`, and in a new `tests/test_family_member_make_jobserver.py`. The holder's Makefile is unchanged. Made and measured on `50178305`, moved onto main `64464d31` (after #891's `a9205e00`) with a clean merge as `4758e645`, then round 1 (`1e94ce04`) from lane 5's review (#950 issuecomment-6253417294), READY at `1e94ce04` on lane 5's re-check (issuecomment-6254597377). **The line.** Under the holder's `make -j2 bootstrap`, `validate`, `park` or `resume`, each member's make printed `make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.` and ran its jobs one at a time. Measured on `50178305` with GNU Make 4.3, in a holder `family.py` made, with two members it scaffolded and added, each member's Makefile giving its target two prerequisites that need nothing of each other, each writing a start and a stop line: two warnings per verb, one per member, and every member's trace serial. - The holder's rules run `scripts/bootstrap.py` and `scripts/siblings.py` with no `+`, so make closes the jobserver's descriptors for them, and `Popen` closes the rest. - The member's make still found `-j2 --jobserver-auth=3,4` in the `MAKEFLAGS` it inherits. - The rule the warning names is the holder's pinned Makefile, which the person does not own. **The fix, the issue's second direction.** `member_make_env()`, in both scripts, gives a member's make this run's environment with the jobserver word (`--jobserver-auth=` or `--jobserver-fds=`) and every `-j` word taken out of `MAKEFLAGS`, where it names a jobserver. It is used by `run_make` (`bootstrap`, and `--members-make validate`) and by `dispatch` (`--make park`, `--make resume`). Now each member's make prints nothing and runs its jobs one at a time, as it did; its flags are those of a plain run. - Every other word is kept: `-k`, `-s`, and a variable from the holder's command line. - `MAKEFLAGS` is split as make splits it (`MAKEFLAGS_WORD`, `(?:\\.|[^ \t])+`): only at a space or a tab, a backslash keeping either in a value. So `NOTE='a -j3'` reaches the member whole, and so does a value holding a no-break space (U+00A0), a narrow one (U+202F) or a newline, which make passes through raw (round 1, lane 5's MUST 1: round 0 split at every character Python's `\s` matches, so under `-j2` `NOTE=x<U+00A0>EXTRA=injected` reached the member as `NOTE=x` and `EXTRA=injected`, measured). - A `MAKEFLAGS` that names no jobserver is left byte for byte, and the environment handed on is a copy: this run's own is untouched. **Why not hand the jobserver on** (option 1, measured on 4.3): a `+` on the holder's rules with the descriptors passed through ran each member's jobs together, but a `+` line runs under `make -n` too, so `make -n bootstrap` fetched every member and leg; descriptors `MAKEFLAGS` names by number are no proof they are the jobserver's; and the member's make is `make` on PATH, not the holder's (make exports no `MAKE`), so it may not read its parent's jobserver word (4.3 stops at 4.4's `fifo:` path, exit 2). On macOS's 3.81 (`--jobserver-fds=3,4 -j`) members warned and ran serially, and now only run serially. On GNU make 4.4 and later, whose fifo jobserver a member's make may reach today, members now run one job at a time too: #987 is the follow-up for that. **Written in both scripts, not imported,** so a holder that keeps its own `bootstrap.py` with `update-shape.py apply --accept-local` is not refused `update-accept-local-missing-name` for a new name `siblings.py` would import; the new tests hold the two copies to one answer. **Tests:** 43 items in the new file: - under the holder's own `make -j2 bootstrap`, `validate`, `park` and `resume`, no warning, and each member's trace serial with no `-j` in its flags; - under `make -k -j2 bootstrap NOTE='a -j3'`, each member's flags the same as under `make -k bootstrap NOTE='a -j3'`; - both scripts' `member_make_env` on 12 spellings of a jobserver: GNU make 4.3's (with `-j16` among them), 4.4's `fifo:`, 3.81's, Windows', and 4.3's with a value holding U+00A0, U+202F or a newline, built from Python escapes; - both scripts on six `MAKEFLAGS` that name none, left byte for byte; - both scripts handing back a copy, `os.environ` unchanged (round 1, lane 5's NIT 2). On main's scripts all 43 fail (5 on the warning, 38 for want of `member_make_env`). The run: 1332 passed on 19 files at `1e94ce04`. 18 mutants, nine edits each made in both scripts, were all killed, among them round 0's splitter (3 failed in each), `-j[0-9]?` (lane 5's NIT 1) and `env = os.environ` (lane 5's NIT 2). Each holder takes two `upstream-changed` rows, `scripts/bootstrap.py` and `scripts/siblings.py` (`FAMILY_COPIED_VERBATIM`); the Makefile row stays `unchanged`. Lane: openreposhape-4 (openRepoShape-4) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eviews and the Known limits continuation, with lanes 2, 4 and 5's items: eleven sites left to #1110, the doctor's 000 and 444 mount rows, the #1082 upgrade warning and the #891 and #1103 limits said as main's code does, #1112 and lane 2's two doctor limits named, and the shape copies measured (#921) The fix round on RV1155a, RV1155b, RV1155c and RV1155d, the continuations RV1155d2 and RV1155a2, and the comments lanes openRepoShape-4 and openRepoShape-5 left on #1155: - RV1155c's two MUSTs: `spec/` at 000 is `cannot be listed` and at 444 `spec/.git: cannot be read`; `scripts/` at 444 is `INVALID (manifest, pins)` on 3.14 as on 3.12. - Every SHOULD (a 3, b 2, c 3, d 13) and every NIT but RV1155a's NIT 7, RV1155a2's eight among them. - Where lane 5 and a reviewer word one line, one text covers both: #891 (d SHOULD 6, lane 5 SHOULD 7), #1103 (d SHOULD 7, lane 5 SHOULD 4) and #1090 (c's first NIT, lane 5 NIT 14). - KNOWN_OPEN in tests/test_path_guard_hygiene.py holds eleven sites, so both lines say eleven. - #1112 is a known limit; lane 2's two doctor limits (#975) and its test-only gaps (#975, #1050) are listed, and the "INVALID, not DRIFTED" sentence holds for a mount this user cannot list or read. - The shape-copy measurement fills its placeholder; the "Before tagging" pointer is gone. - The pipx claim carries RV1155d's qualifier everywhere it is made. - v1.0.0's tab-in-a-pin line is closed (#1015); its bare number or boolean in a plan's text field is narrowed (#1016). - `update-shape.py check` is named with `--at <release-commit>`, and the measurement says main `038dafb` was the upstream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-5 (openRepoShape-5)
Claim: #890 (comment)
Follows #886 (#884), which landed as
e7039b71. The branch is restacked onto that squash as58e4ddf0: three merges, #886's final head85c20783, then its squash with this branch's side for the two files, then main. Its tree is30ba7a3e, the merge ofd2be39dcwith main0d5d2b11. Fix round 1, from rv884's review of this pull request (issuecomment-6250054923), is one commit on it,013b9402. A NIT round, from rv884's re-check (issuecomment-6250467939), is one more,41f781fd, which adds a test only and which the runs below cover.#890's two lines, from rv884's NIT 1 and NIT 2 in its re-check of #886 at
dbd3a6dd(#886 issuecomment-6249507909). One commit ondbd3a6dd, and fix round 1 on the restack, in the family holder's pinnedtemplates/family-root/scripts/bootstrap.pyand intests/test_family_holder_bootstrap_texts.py, and nothing else. Each shape was probed under the holder's ownmake bootstrap(the member's make at depth 1) and withbootstrap.pyrun straight (depth 0), with GNU Make 4.3, dash 0.5.12 as/bin/shand git 2.43.0.1. Three nested-make shapes read a member's refusal as a finding (
MAKE_FAILED_RE,MakeErrors.said).$(MAKE) mid, then its ownexit 2;midruns-$(MAKE) inner, andinnerexits 1. make printsmake[3]: *** [...] Error 1, thenmake[2]: [mid] Error 2 (ignored), thenmake[1]: *** [bootstrap] Error 2. Atdbd3a6ddthe(ignored)line put the depth back at 2, the ignoring make's own, so the member'sError 2at depth 1 was passed over, and the line saidexited 1.$(MAKE) inner || true, then-false, thenexit 2. Atdbd3a6ddonlyError 2 (ignored)was a marker, soError 1 (ignored)changed nothing, and the line saidexited 1.$(MAKE) inner || true, then-@kill -KILL $$, thenexit 2. make printsmake[1]: [Makefile:3: bootstrap] Killed (ignored), orTerminated (ignored)for SIGTERM. Atd2be39dconlyError <code> (ignored)was a marker, so the line saidexited 1for either signal;281df263said 2.[...] <what ended it> (ignored)line is a marker whatever ended the command:Error <code> (ignored)for a code,Killed (ignored)orTerminated (ignored)for a signal. It sets the depth to -1, as before any***line, so noError 2after it is passed over until another***line comes. Why that is safe (rv884's argument): in a sequential run, the make that printed the line goes on, and if it fails later it prints a***line of its own first, which sets the depth again; so noError 2after an(ignored)line, with no***line between, can be a make reporting a failed one, whatever ended the ignored command. The rule's code is rv884's patches exactly, its I1 and I17 together and then its Q12 in fix round 1; only comments and docstrings differ from them.dbd3a6dd, three patched copies of it (both changes, the reset alone, the marker alone) and281df263: rv884's 183 case-modes (itscases1.pytocases6.py, and its re-check'sign.py,ign2.pyandign3.py) and 41 more (cases-f886.py,cases-f886b.py,cases-f886c.py), each at both depths: 224 case-modes, 1120 runs.dbd3a6ddin 5 case-modes; the reset alone in 3, and the marker alone in 2.(ignored)line followed by its ownexit 2, run straight. In each,dbd3a6ddnamed 1 and the change names the member's ownexit 2, as281df263did.dbd3a6dd.InnerLets,exited 2), and an(ignored)line leaves the code named before it.58e4ddf0and on its copy with rv884's Q12, over the same 224 case-modes and rv884's three new cases (rv890/tools/extra.py: SIGKILL, SIGTERM, and a-two makes below), each at both depths: 230 case-modes, 460 runs. Q12 differs from58e4ddf0in 4: the SIGKILL and SIGTERM cases, each at both depths, each now naming the member's ownexit 2, as281df263did. No case reads worse. The pattern also takes a line written asmake[1]: [Makefile:3: bootstrap] Segmentation fault (core dumped) (ignored)(checked on the line, not on a run).INNERMOST, run bytest_the_line_names_the_code_of_the_member_s_innermost_command[innermost-under-make]and[innermost], at both depths:LetsBelow, Scenario 1, expectingexited 2;LetsTwoBelow, Scenario 1 one make deeper (the member,mid, thenmid2, which runs-$(MAKE) inner), expectingexited 2, so a depth reset to one above the ignoring make is caught (rv884's Q6, its NIT 2 on this pull request);PassesThenLets, Scenario 2 with-@exit 10for-false, so a code of two digits is a marker too, expectingexited 2. The form with-falseis among the measured cases and readsexited 2at both depths;ThenLets, under-k, a finding and then-false, expectingexited 1: now that every(ignored)line is a marker, an(ignored)line must leave the code named before it (rv884's I4);PassesThenKilled, the signal:$(MAKE) inner || true, then-@kill -KILL $$, then the recipe's own refusal, expectingexited 2;PassesThenTerminated, the same with-@kill -TERM $$, expectingexited 2, so a marker that took onlyError <code>andKilledfails (rv884's R4, its NIT on the re-check).281df263dbd3a6dd58e4ddf0LetsBelowPassesThenLetsThenLetsLetsTwoBelowPassesThenKilledPassesThenTerminateddbd3a6dd, at both depths. They now shareFINDSandREFUSES, the finding and refusal commands, in place of the seven copies the table held; their bytes are unchanged, checked by evaluating both tables.2.
MakeErrors' list of limits misses a-kshape (docstring only).-k,a: $(MAKE) innerA, whose command exits 1, thenb: -$(MAKE) innerB, whose command exits 3. The lastErrorline is the command's in the make the-let fail, so 3 is named, though the failing command exited 1. Reading it right would take a code kept per depth; it stays a limit.|| trueitem now reads "with no(ignored)line between", since Scenario 2 is no longer a limit, and keeps the-snote: a make run with-sprints no(ignored)line. Atd2be39dcthe item was false for a signal's(ignored)line:$(MAKE) inner || true, then-@kill -KILL $$, thenexit 2readexited 1though such a line came between (rv884's NIT 1). It is true since fix round 1, which makes that line a marker. Scenario 1 is not listed, since line 1 fixes it.-kshape (rv884'sk-sub1-then-letfail) readsexited 3at head,dbd3a6dd,82a84f88and281df263;$(MAKE) inner || true; exit 2, and-$(MAKE) -s innerthenexit 2in a make run with-s(the holder'smake -s, orMAKEFLAGS=srun straight), readexited 1at head and atdbd3a6dd, as the list says.Pinned copy and docs.
bootstrap.pyis inFAMILY_COPIED_VERBATIM, so each holder takes oneupstream-changedrow for it on its next update. Its mode stays 100755, and its imports are unchanged.--helptext changed, sodocs/cli.mdis unchanged. No sentence ofAGENTS.md,templates/family-root/AGENTS-shape.md,templates/family-root/README.mdorREADME.mdspeaks of the make line (grep).Fail on older code, with fix round 1's test file (still 57 items: the new members run inside the two
[innermost*]cases). The NIT round'sPassesThenTerminatedreads 1 on58e4ddf0anddbd3a6ddand 2 on281df263, at both depths, so it adds to the same two failures:58e4ddf0's code (this pull request before fix round 1): 2 failed, 55 passed:[innermost-under-make]and[innermost], throughPassesThenKilled;dbd3a6dd's code: 2 failed, 55 passed:[innermost-under-make]and[innermost], throughLetsBelow,PassesThenLets,LetsTwoBelowandPassesThenKilled;281df263's code: 3 failed, 54 passed:[innermost-under-make],[innermost]andtest_a_line_that_comes_in_pieces_is_read_whole;Mutants at head, each run against the whole test file: 45 made, 41 caught. They are #886's fix-round mutants (its first 19, rv884's X1-X12 and N1-N5), restated where the code changed; rv884's I1, I4, I8 and I17 from its re-check of #886, with I1 and I17 reversed, since head holds them; P3 and P4 for this change's first hunks; and rv884's Q6, Q11 and Q12 from its review of this pull request, Q12 reversed, since head holds it. The members in brackets are the ones each mutant reads wrong, measured on a mutated copy at both depths, at
013b9402(beforePassesThenTerminated) except for the NIT round's rows.41f781fd: 4 more runs, 3 caught. rv884's R4 ((?:Error \d+|Killed)only) and this round's S1 (what ended it at most 8 bytes, soTerminatedis missed) are caught byPassesThenTerminatedalone; Q12 reversed is caught byPassesThenKilledandPassesThenTerminated. rv884's R7 (no space before(ignored)) survives and is equivalent: make always prints the space, and it differs from head in none of the 230 case-modes (rv884'ssweepr7.log);PassesThenTerminatedreads 2 under it.Error \d+only,58e4ddf0's pattern)[innermost*](PassesThenKilled; at41f781fdalsoPassesThenTerminated)(?:Error \d+|Killed)only), at41f781fd[innermost*](PassesThenTerminated)[^\n]{0,8}for what ended it), at41f781fd[innermost*](PassesThenTerminated)self.depth = depth - 1)[innermost*](LetsTwoBelow)[innermost*](InnerLets)Error 2 (ignored)); P4 (onlyError \d (ignored))[innermost*](PassesThenLets,PassesThenKilled)min(self.depth, depth),dbd3a6dd's code)[innermost*](LetsBelow,LetsTwoBelow)min(self.depth, depth + 1))[innermost*](LetFail,LetsBelow,LetsTwoBelow,PassesThenLets,PassesThenKilled)(ignored)line clears the code)[innermost*](ThenLets)(ignored)line not read[innermost*](LetFail,LetsBelow,LetsTwoBelow,PassesThenLets,PassesThenKilled)(ignored)line sets its own depth; N5, it falls through[innermost*](InnerLets,LetsBelow,LetsTwoBelow)max(self.depth, depth)[innermost*](InnerLets,LetFail,LetsBelow,LetsTwoBelow,PassesThenLets,PassesThenKilled)[innermost*](R1 and R8 also[last-under-make]; R8 also the pieces test; X1 also bothtold_apartcases)<=for<), H12[last-under-make][innermost]told_apartcases, both[innermost*]test_a_member_s_question_shows_before_its_answer_is_typedtest_no_advice_beside_no_member_updated_with_every_member_checked_outcasetest_what_a_member_s_make_leaves_on_stderr_is_passed_on_as_writtensplitlines)[signal]\s*$dropped; make's***lines carry nothing after the code), X6 (the unended remainder read at EOF; make always ends its line), X9 (passed over only one level deeper; makes nest one level at a time) and P3 (an(ignored)line resets the depth to 0, not -1; no line's depth is below 0, sodepth < 0anddepth < -1are both always false).Runs, through
run9s.shwithSHARDS=3, with no tracked changes. The files:tests/test_family_holder_bootstrap_texts.py,tests/test_family_bootstrap_gate_order.py,tests/test_bootstrap_spelling.pyandtests/test_pinned_copy_text.py; the two thatgit grep -l 'family-root/scripts/bootstrap' -- testsnames,tests/test_family.pyandtests/test_update_shape_kept_helper.py; the trio,tests/test_repo_hygiene.py,tests/test_agents_md_codes.pyandtests/test_cli_reference.py; and five more that run the holder's bootstrap:tests/test_family_gitmodules_values.py,tests/test_family_head_lost_gitmodules.py,tests/test_family_members_not_a_list.py,tests/test_bootstrap_without_git.pyandtests/test_family_makefile_siblings.py.41f781fd: 1178 passed, rc 0 (shards 222, 429 and 527); the texts file alone, 57 passed, rc 0.41f781fd, 57 passed, rc 0; the full set at013b9402, which differs from41f781fdonly in the texts file's new member, 1178 passed, rc 0 (the same shards).exited 2for a finding, andmake -kkeeps itsErrorline (#884) #886's 1049 because main has since added tests to these files.Merge checks,
git merge-tree --write-treeof41f781fd, after a fresh fetch:2d372bb5, one commit past #886's squashe7039b71, touching neither filee55b04f33b15de03, which edits other parts ofbootstrap.pya454759a; main and #889 merge clean too, tree5ad6e5d1d2be39dcwith the predicted squash of the family root's bootstrap.py: make's stderr is read a line at a time and the innermost command named, so a member whose make runs another no longer readsexited 2for a finding, andmake -kkeeps itsErrorline (#884) #886 conflicted in both files, and taking this branch's side gave tree30ba7a3e, the merge ofd2be39dcwith main0d5d2b11. On a detached commit at that tree,3133e841, the texts file,tests/test_family_gitmodules_values.pyandtests/test_pinned_copy_text.pygave 291 passed, rc 0 (git 2.43). The restack58e4ddf0has that tree.Sonar-style checks.
dbd3a6ddappears anywhere else intests/,scripts/ortemplates/, in exact text. With literals blinded, the same holds for fix round 1's and the NIT round's lines, and over the whole change since281df263no window of 10 or 8 lines matches; at 6 lines only the test file's import block does.INNERMOST's members matched each other in two 10-line windows atdbd3a6dd(rv884's note on the family root's bootstrap.py: make's stderr is read a line at a time and the innermost command named, so a member whose make runs another no longer readsexited 2for a finding, andmake -kkeeps itsErrorline (#884) #886); withFINDSandREFUSESshared, none do.and.MakeErrors.saidstays 6, its branches unchanged (if not found,depth_said or 0,if ignored,code == b"2" and ...,if code and not ...). No other function's code changed. The longest added line is 75 columns; the NIT round's longest is 74.Not here.
-kshape of line 2 still names the let-fail command's code; reading it right would take a code kept per depth.Closes #890
🤖 Generated with Claude Code
Summary by Sourcery
Fix bootstrap failure parsing so ignored command results reset nested-make tracking and subsequent member failures are reported accurately.
Bug Fixes:
Enhancements:
Tests: