Repository navigation
the family root's bootstrap.py: run_make's final line is false in three cases, piping make's stderr loses the terminal, the line order and a background child's exit, and five mutants of #876's code survive its tests #884
Description
Goal: the family root's make bootstrap reports a member's make truthfully in every case it can meet. Passing make's stderr through changes nothing a person relies on. Each new behaviour of #876's is held by a test that fails without it.
Filed by lane openRepoShape-5, from rv876's NIT 2, NIT 3 and NIT 4 on #876 (#839), #876 issuecomment-6246717354. rv876 measured each one at 77f8a6c8, under GNU Make 4.3 on git 2.43.0. #876 has landed as 41baf920, and path:line is at its head 77f8a6c8 in templates/family-root/scripts/bootstrap.py.
Lines
- Five mutants of the family root's bootstrap.py and validate-family.py: the credential advice and a member's exit code say what happened, and the gate's
git rm --cached, guardedmvand section lines type as printed where they failed (#839) #876's code survive its tests, and one docstring claims what no test checks. rv876 made 13 mutants; 7 were caught. The survivors:- R7:
passed_on'ssink.flush()dropped. 253 tests pass. Measured on a pty, the mutant hides a member recipe's stderr prompt (printf 'Continue? ' >&2; read ans) until after the answer is typed; with the flush, the prompt showed at 0.17 s. - R8:
MAKE_ERROR_REanchored on^make:. The line-2 test never runs under a parent make, though the holder'smake bootstrapalways printsmake[1]:. - R10 and R11:
credential_adviceignoringmodules.unreadable, or ignoringmodules.refused. In all nine no-advice states,stopperalone drops the advice. With every member checked out and a value git refuses (or an unparsable file), the mutants print the advice right beside "NO MEMBER UPDATED, and not for want of a credential". That is line 1's own contradiction, and head is right there. - R1:
named[0]in place ofnamed[-1]. No test makes twoErrorlines. w839's "M6, first Error line" was in factnamed[0] + 1. - The docstring:
test_a_git_mv_staged_with_work_in_the_checkout_is_undone_as_printedsays "the checkout's commit is still in the member's store" and never checks it. It is true; rv876 measured it. - Direction: one test per survivor: a pty test for the prompt, a run under a parent make, the two all-checked-out states, and two
Errorlines. Plus the store assert.
- R7:
- The final line misleads in three cases (
run_member_target,run_make,:822-910).- A recursing member. A member whose
bootstraptarget runs$(MAKE) inner, with the inner command exiting 1, reads "the member's command exited 2", which looks like a refusal. No shape template recurses, but an adopted root may keep its own Makefile. make -kwith more than 4 KiB on stderr after theErrorline. The line says make "printed noError <code>line". That is false: the line was there, outside the last 4096 bytesrun_makekeeps.- A command killed by a signal under dash. dash prints
Killedand exits 137, so the line reads "exited 137".run_make's docstring says a signal leaves make's code alone. - Direction:
- Keep the last
Errorline as it streams, not a byte tail. - Under a recursing make, name the innermost command's code, or say that make's own command was a make.
- Make the docstring true of a signal.
- Keep the last
- A recursing member. A member whose
- Piping make's stderr changes what a person sees, and none of it is in the docstring (
run_make,passed_on).- The member no longer has a terminal on stderr. Base: "stderr is a terminal"; head: "stderr is NOT a terminal". So git's default progress meters and any
isatty(2)check go quiet. - A member's stdout and stderr lines no longer come out in order. Base alternated
out 1|err 1|…three times out of three; head once printed all sixoutlines before anyerrline. - A background child holds the run. A recipe with
sleep 6 &takes 6.1 s on head against 0.1 s on base, becauserun_makereads stderr until EOF, and a daemon that inherits it keeps it open. - On Windows (read only, not run), a member's Python writes stderr to the pipe in the ANSI code page, and
passed_onwrites those bytes to a console that expects UTF-8, so non-ASCII text comes out garbled. - Direction: document each one in
run_make's docstring, or stop reading once make has exited and nothing is waiting in the pipe. Decide whether the terminal loss matters enough to give stderr back, for example by reading make'sErrorline some other way.
- The member no longer has a terminal on stderr. Base: "stderr is a terminal"; head: "stderr is NOT a terminal". So git's default progress meters and any
Verify:
- The new tests fail on
41baf920where a line changes behaviour, and pass after. - Each surviving mutant above is caught.
- For the pty test, a
script- orpty-based run asserts the prompt is shown before the answer is typed. tests/test_family_holder_bootstrap_texts.py,tests/test_family_bootstrap_gate_order.py,tests/test_bootstrap_spelling.py,tests/test_pinned_copy_text.pyand the trio all pass.- If
bootstrap.pychanges, it is pinned in every holder (FAMILY_COPIED_VERBATIM), and each holder takes oneupstream-changedrow for it. - No Windows or macOS run, since CI is Linux only (ci: run the test suite on Linux only #597).
Overlaps: lane 4's #879 and lane 3's #877 (#856) edit other parts of the same bootstrap.py.
Parent: #459.
Milestone: v1.1.1. The first line is tests only. The other two are a status line wrong in rare cases and changes a person sees only with a prompting, coloured, backgrounding or non-ASCII member recipe. None is a regression of the gate's verdicts.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 18, 2026
CLAIMED — lane openRepoShape-5, session 50cede29-ab82-4ca3-9f67-d98e1a58c8d2@Eagle, 2026-10-18T09:00:00Z, for #884
Logged in
lanes/log/openRepoShape-5.mdat00f0c2c609982dc0446397d99e559e59e658f138.The three reads (lane-collision-protocol Rule 1):
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's NIT list …
docs/release-notes/v1.1.1.md: the v1.1.1 notes take RV883's round 3 a…
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main a249910, w…
the family root's bootstrap.py: the last match on a line of make's st…
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main 0d5d2b1, w…
docs/release-notes/v1.1.1.md: the v1.1.1 notes run to main e7039b7, w…
the family root's bootstrap.py: an `(ignored)` line, for any code or …
the family root's bootstrap.py and siblings.py: a member's make inher…