Skip to content

chore(release): 2.7.6 -> main - #66

Merged
LESdylan merged 3 commits into
mainfrom
develop
Aug 23, 2026
Merged

chore(release): 2.7.6 -> main#66
LESdylan merged 3 commits into
mainfrom
develop

Conversation

@LESdylan

Copy link
Copy Markdown
Member

Promotes v2.7.6 to main. Everything here has already gone through the full gate on develop.

What ships in 2.7.6

  • Separate debug and release build configurations (chore(release): 2.7.6 -- separate debug and release build configurations #65). MODE=debug|release|relwithdebinfo, each a deliberate answer rather than a side effect of which flags happened to be set. Release is 462 KB and carries no debug information of ours — not because anything is stripped afterwards, but because release never compiles -g in. OPT=1 still means exactly MODE=release, byte for byte.

    Two real defects fell out of writing the test: SAFE and OBJ_DIR both keyed on ifdef OPT, so OPT=1 and MODE=release picked different allocators, and the optimized modes shared the debug object tree — which handed the linker ASan-instrumented objects under a link line with no -fsanitize. Both now key on MODE.

  • make user-install leaves hellish on PATH (67508ad), not just on disk. The installer placed the binary and added an exec hook, but nothing on either route put $PREFIX/bin on PATH — so hellish update and command -v hellish failed on a machine that had just installed it.

  • Release notes and code comments now cite issue [bug] a release published since the last check stays invisible for a day #64 for the update-freshness fix; 2.7.5 cited the number GitHub had assigned to the pull request.

Gate on develop (023b785 / 8f60e51)

  • CI — 16/16 jobs green, including Interactive · pty gates, Gates · cli + login + install + help + cd + update-config, Tests · suite + scripts + leaks, Hard corpus + allocator parity, 42 Norm, and all three build configurations (opt SAFE=0, opt SAFE=1, debug SAFE=1).
  • Platforms — 16/16 green across alpine musl, arch, debian, fedora, opensuse, rocky, ubuntu 22.04/24.04, void and linux arm64, under both gcc and clang.
  • Locally: golden suite 3790/3790, pty suite 30 ok / 0 failed / 4 skipped.

Tag v2.7.6 follows the merge.

LESdylan and others added 3 commits August 23, 2026 17:50
`make user-install` did both of the things it advertises -- copied the
binary to $PREFIX/bin and appended an exec hook to your login shell's rc --
and a new user still met this:

    $ hellish update
    hellish: command not found

Nothing on either install route ever put $PREFIX/bin on PATH. The hook execs
an ABSOLUTE path, so the shell came up perfectly and the gap stayed
invisible: what was broken was not the shell, it was its NAME. `hellish`,
`hellish update`, `command -v hellish`, and every tool that looks a shell up
by name answered "not found" on a machine that had just installed it.

~/.hellishrc argued itself out of the fix. Its section 3 said a PATH line
here is redundant, because a LOGIN hellish sources /etc/profile and then
~/.profile, which is what puts ~/.local/bin on PATH. True of `make my_shell`
+ chsh. False of this route, twice over:

  * user-install's hellish is exec'd from an INTERACTIVE rc. It is not a
    login shell, so it reads neither /etc/profile nor ~/.profile.
  * Debian/Ubuntu's ~/.profile adds ~/.local/bin only `if [ -d ]` -- and on
    a first install, THIS INSTALL is what creates that directory. Even the
    login route would not have picked it up before the next logout.

That reasoning came out of #51, where an unguarded prepend in the template
was teaching people to copy PATH edits around. Dropping it was right; what
was wrong was generalising it to a route the login chain does not reach. So
the template still ships no PATH line, and the INSTALLER now owns one block.

tools/seed_hellishrc.sh -- the seeder both routes already share -- grows
--path-dir and --strip-path, and maintains one marker-delimited block
(`# >>> hellish path >>>`) in ~/.hellishrc naming the directory actually
installed into. The rule that file exists for is untouched: an existing
~/.hellishrc is still never clobbered, because only the text between the
markers is ever rewritten. It is `sh -n`-checked before it replaces
anything, for the same reason the rc hook is: a config that will not parse
greets you on every terminal, and this script is the one that wrote it.

user-install.sh passes --path-dir "$DEST_DIR", makes the same guarded
prepend in the rc hook before it execs -- so `hellish` resolves in bash too,
and in a HELLISH_NO_EXEC=1 session -- and strips the block on --uninstall.
Both prepends are `case`-guarded: an rc gets re-sourced by every nested
interactive shell, and an unguarded one stacks copies until PATH is mostly
duplicates. `make my_shell` passes no --path-dir; /usr/bin needs none.

tests/user_install_path_test.py pins all of it against a temporary $HOME,
with --bin so nothing compiles and the real $HOME is never touched: the name
resolving after install, the same thing end to end in a real pty, no
duplicate entries across three re-sources, the rc hook, a custom PREFIX, a
hand-written ~/.hellishrc surviving intact, re-install idempotence, and
uninstall removing only our block. Against the old scripts it fails ten
checks, the pty one showing the report verbatim.

It runs in CI twice over, and both are deliberate. tests/pty_suite.sh globs
tests/*.py, so `make pty-test` picks it up with nothing to remember. It is
also named in the gates job, because this gates the INSTALLER -- no
shell-behaviour job would otherwise ever run user-install.sh, and an install
route that no CI job executes is exactly how this shipped.
Development instrumentation and shipping optimization are different jobs
and one set of flags cannot do both. The Makefile had two configurations
selected by `ifdef OPT` and no name for either, so the middle case — an
optimized build you can still attach a debugger to — did not exist, and a
5.6 MB `build/bin/hellish` read as the shipped binary when it never was.

Three named configurations, chosen with MODE=:

  debug (default)   -O0 -g3 -ggdb, ASan+LSan, libc malloc     develop
  release           -O3 -DNDEBUG, LTO, --gc-sections, no -g   ship
  relwithdebinfo    -O2 -g -DNDEBUG, no sanitizer, no LTO     optimized bugs

462 KB / 3.0 MB / 5.6 MB respectively. Nothing is stripped afterwards:
release carries no debug information because release never compiles -g in,
which is why strip recovers ~1 KB from it — 807 bytes of libgcc
crtfastmath.c that -ffast-math pulls in already compiled with -g. None of
it is ours. No sanitizer, assertion, symbol or dependency was removed from
the debug build to get there.

OPT=1 stays working and now resolves to exactly MODE=release, byte for
byte. It used to disagree with itself: SAFE defaulted off `ifdef OPT`, so
the two spellings of one configuration picked different allocators and
produced different binaries. SAFE now keys off MODE.

Fixes a real defect found while writing the test: OBJ_DIR also keyed on
`ifdef OPT`, which covered the OPT benchmark build alone and left
MODE=release and MODE=relwithdebinfo parked in the debug tree. make
rebuilds on a changed prerequisite, never on a changed flag, so a plain
`make MODE=release` after a debug build fed the linker ASan-instrumented
objects under a link line with no -fsanitize:

    func_retire.o: undefined reference to `__asan_report_load4'

`make re` hid it. Objects now live in build/obj-<mode>-<allocator>.

tests/build_modes_test.py pins all of it — 20 checks read `make flags`,
which resolves a configuration without compiling, so the test costs
nothing and cannot be fooled by a stale object tree. 3 of its checks fail
against the pre-fix OBJ_DIR. tests/link_closure_test.py now globs
build/obj* and picks the newest tree rather than the first name it
recognised, which is what its docstring always claimed.

Also corrects the update-freshness fix to reference issue #64; 2.7.5 cited
the number GitHub had assigned to the pull request.

make norm clean · golden suite 3790/3790 · pty suite green
chore(release): 2.7.6 -- separate debug and release build configurations
@LESdylan
LESdylan merged commit 4760c94 into main Aug 23, 2026
74 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant