The last unit over the cap is now github.com/kuhyx/digital-wellbeing, cloned
at ~/digital-wellbeing, and `--warn` is gone from the directory-depth-cap
hook. `check_directory_depth.sh --all` exits 0 with zero violations, down from
46 at the start of the session. That was the point of the campaign.
History was filtered across all three paths the unit has lived at (63
commits); the current path alone holds 2.
The six suites that test this code lived in linux_configuration/tests/ rather
than beside it, so they were filtered separately (24 commits) and merged in as
a second root. A path filter of the unit alone would have left them here,
testing code that had left the repo -- and their names would still have been
in shell-tests.yml's hardcoded arrays, failing CI on missing files.
linux_configuration/lib/common.sh is vendored into vendor/ rather than trimmed
to the four functions actually used: set_actual_user_vars calls two of the
others, so a trim breaks silently. It is in vendor/ and not lib/ because
test_music_parallelism.sh copies the unit's own lib/ into a scratch worktree
while stubbing the shared lib; in one directory the real common.sh overwrote
the stub, and the suite silently measured the wrong library.
Running the callers caught what shellcheck and grep both missed:
check_and_enable_services.sh died with "DW_REPO: unbound variable" because the
definition sat below its first use. It now runs clean and reports ok for every
extracted-unit check.
Two long-standing live defects fixed as a consequence. The pacman-wrapper
drift manifest embeds ABSOLUTE paths and had named deleted scripts/ paths
since the flatten, so the check reported a permanent false "stale or
tampered"; it now verifies, with unchanged hashes proving the extracted bytes
are identical. And the last two stale live references are gone: 8 -> 0.
The two pre-commit excludes for setup_midnight_shutdown.sh are dropped rather
than moved. lsattr shows nothing in the unit is chattr +i any more, and the
fixer hooks leave the file alone when allowed to run.
Removing 80 shell files also shrank the jscpd denominator enough that the
virtualenv/tqdm clones inside the GENERATED .ci-mirror-venv/ tipped the repo
to 2.09% and blocked this commit, which adds no duplication. That directory is
the same vendored third-party shell the ignore list already excludes as
.venv/, just under another name; jscpd walks the working tree rather than the
index, so being untracked did not spare it. Excluded by name: 1.74%.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
Two files under the cap.
test_security_hardening.sh (423) keeps its filename -- shell-tests.yml
runs the suite by name -- and its five sections move into three sourced
libs. They are top-level blocks, not functions, so each is wrapped and
called in the original order; the counters and LIVE_SECTION stay in the
entry, which sourcing shares. Verified by diffing a full run against the
same suite from a detached worktree at HEAD: byte-identical output, same
exit status, still 18/1/5 on this host. The one failure is pre-existing.
Linting a lib alone turns a bare LIVE_SECTION=1 into SC2034, since its
only reader is test_result in the entry. A live_section() setter makes
the write a real reference, so no suppression was needed.
The mutation-driver split was already in the tree from the previous
session and did not run: the operators had moved to
_session_autopsy_mutations.py but the driver still named Mutation
without importing it, so mypy and pylint both reported undefined-variable.
Restored the import; the script now reports all 12 tests killed.
block_compulsive_opening.sh (705) is deliberately untouched and now says
so in the contract. install_all copies the running script to
/usr/local/bin, so an entry sourcing lib/ would resolve SCRIPT_DIR there,
find nothing, and leave beeper, signal-desktop and discord unlaunchable
with a failing pacman hook. Splitting it means teaching the installer to
copy the libs -- a refactor, not a line-count split.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Test 10 only knew the retired shutdown-schedule-guard.path, so it
reported a skip while guard-file@shutdown-schedule.path was actively
protecting /etc/shutdown-schedule.conf. That understated the real
protection in the same way tests 2, 3 and 5 did before the last
commit.
It now accepts the guard-lib unit and passes. The
disabled-is-intentional branch stays for hosts running neither unit.
Host: 19 passed / 0 failed / 5 skipped. Container: exit 0.
The suite reported four failures on this host and none of them meant
protection was missing.
Tests 2, 3 and 5 checked hosts-guard.path, hosts-bind-mount.service
and nsswitch-guard.path. The 2026-07-17 guard-lib refactor replaced
those with templated units — guard-file@hosts.path,
guard-bind-mount@hosts.service, guard-file@nsswitch.path — which are
all active. That is also why the legacy units stop a second after
boot: they are superseded, and the old nsswitch guard retriggered
itself into systemd's start limit fighting the new watcher. Each check
now accepts either generation, and the bind-mount check also accepts
the read-only mount on /etc/hosts, which is the real invariant.
Test 10 now treats a *disabled* shutdown-schedule-guard as intended
rather than broken: the poweroff flow it protected was replaced by
night-lockdown-enter.sh. An enabled-but-inactive unit still fails.
That check also had a shell bug — `systemctl is-enabled` prints the
state and exits non-zero when disabled, so `|| echo disabled`
appended a second line and never matched.
Verified protection is genuinely intact rather than assuming it:
/etc/hosts is mounted ro,noatime and both it and /etc/nsswitch.conf
carry the immutable flag. Host now reports 18/0/6. A container with
faked host markers still reports 10 failures, so the suite has not
been softened into always-green.
No system state was changed.
The last three exclusions are gone.
test_i3blocks_efficiency.sh only ever needed strace and ptrace. It went
unverified earlier because Docker's bridge network has no DNS on this
machine, so pacman could not install strace; --network=host works, and
the test passes. The job installs strace and adds SYS_PTRACE.
test_hosts_guard_pacman_integration.sh asserted three symbols the
guard-lib refactor renamed (pacman_hooks_manage_hosts_guard ->
pacman_hooks_manage_guard_lib, and similar). The feature was intact;
only the assertions were stale.
test_security_hardening.sh now separates live-host checks from
repository checks. Off-host the live ones skip, so it is green in a
container while still running its repository checks — and on the real
host it still fails loudly when a guard unit is down.
That last part needed care: the first detection attempt used
`systemctl is-system-running`, which exits non-zero on a degraded
system — precisely the state a failed guard unit produces. It masked
all four real failures. Detection now tests for /run/systemd/system
plus the installed guard payload, which unit health does not affect.
Verified: all 8 arch tests pass in a container; the same
security-hardening file still reports 4 failures on this host.
Steam/browser mutual-exclusion daemon was unusable in its current state.
Removed all code, install tooling, and every reference across
install_core_system.sh, check_and_enable_services.sh, the security
hardening test suite, and CLAUDE.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Move all linux_configuration scripts into two semantic categories:
- single_use/: scripts run once manually (fresh install, fixes, setup)
- periodic_background/: scripts run by systemd timers or daemons
- Preserve existing subdirectory structure within each category
- Fix lib/common.sh source paths for new directory depths
- Fix CONFIG_DIR depth in setup_periodic_system.sh and check_and_enable_services.sh
- Update all references in tests, fresh-install/main.sh, nix modules, and docs
- Fix check_polling_antipatterns.sh false positives (||, regex |, case patterns, jq strings)
- Fix pre-existing mypy exclusion path and type annotations for moved tools/ directory
- Rewrite check_polling_antipatterns.sh using awk (no bash regex loops); add require_serial: true