Bootstrap/package re-review

Verdict

No. The recent commits solve several important findings, but the current tree still has concrete bootstrap failures and contract inconsistencies. This assessment is based on the code and local checks, not on the earlier review document.

The supplied URL currently returns 404, so I could not reliably map every sentence in that document. The status below independently audits the current implementation.

What is solved

Unresolved findings

1. Fresh Debian bootstrap is broken [high]

setup/packages/apt:14 registers pikchr-cli, which is unavailable in the configured Debian 12 repositories. --all selects every APT entry, counts this as a failure, and bootstrap.sh exits because it runs with set -e.

This violates the stated Ubuntu/Debian contract. Either use an available installation method or narrow and test the supported distribution contract.

2. bash-completion is incorrectly skipped [medium]

setup/packages/apt:24 uses bash as the command probe for the bash-completion package. install_apt_package accepts either the command or package as proof of installation (setup/lib/package-installer.sh:39-42). Since Bash is normally already present, a fresh system can skip bash-completion even when that package is absent.

The simplest fix is to use the package database as the authoritative check for APT entries.

3. GitHub latest-release failures are masked [medium]

.local/lib/sh/github.sh:5-8 pipes curl into sed without pipefail. A failed request can therefore return success with an empty version. A direct check against a nonexistent release URL returned HTTP 404 but function status 0.

Capture the curl result first, then strip the path. This remains plain POSIX shell and removes ambiguity.

4. Manifest version claims do not match behavior [medium]

Most installers return success when a command merely exists, without checking its declared version (setup/lib/package-installer.sh:39-41, 60-62, 102-104, 151-153, 178-180, 244-246, 295-297, 323-325, 385-388). Yet README.md:47-50 calls manifests the source of truth for versions.

Under a suckless bootstrap contract, presence-only behavior is reasonable: this is a fresh-machine installer, not a full state reconciler. Prefer documenting pins as versions used for new installs rather than adding many fragile version parsers. Node is currently an exception because it is actively selected through fnm.

5. Platform contract is incomplete [medium]

Go, Rustup, and GitHub-release assets are hard-coded to amd64/x86_64 (setup/lib/package-installer.sh:335,405; setup/packages/github-release). README.md:90-93 says only Ubuntu/Debian.

Hard-coding one architecture is a valid simplification if intentional. State x86_64 Ubuntu/Debian and fail early with a clear architecture check; do not build an architecture abstraction unless another machine is actually needed.

6. README describes two competing bootstrap paths [low]

The “Fresh machine” section links files but never runs setup/install-tools.sh --all (README.md:7-21), although the later section says that is the bootstrap path. It also recommends unpinned mk@latest (README.md:33-37) while the manifest pins mk. The structure listing omits the package manifests and installer.

Choose one blessed command—preferably the repository bootstrap.sh—and keep optional mk targets separate.

7. Neovim’s standalone prerequisite is undocumented [low]

setup/setup-neovim.sh:23-25 now requires jq for GitHub’s asset digest. The documented manual setup installs only Git and curl before offering mk neovim. Full bootstrap installs jq, but the advertised standalone path does not.

8. No focused tests protect the plain-text interface [low]

There are no tracked tests for manifest shape, duplicate names, dispatcher argument counts, APT cache behavior, or mocked download failure propagation. The implementation is intentionally shell-heavy; a small shell test script with fake commands would preserve simplicity better than adding a test framework.

Suckless/extendability assessment

The direction is good: shell scripts, line-oriented manifests, explicit methods, no framework, and no generated configuration. The main problem is not lack of abstraction; it is that the declared contract is wider than the code actually supports.

Keep the current basic design. Prefer these reductions:

  1. Make the support contract explicit: fresh x86_64 Ubuntu/Debian machine, install missing tools at pinned fresh-install versions.
  2. Remove the bad APT entry or move Pikchr to an existing registered installation method.
  3. Let dpkg-query alone determine whether APT packages are installed.
  4. Fix gh_latest_version with one captured curl result.
  5. Make README point to one bootstrap path.
  6. Add one small, dependency-free shell test harness.

Avoid adding a generic package DSL, architecture matrix, or universal version-comparison layer until there is a real second platform or convergence requirement.

Checks performed