aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
blob: 5df16b3f07637c0740f7a94d9b9fb060038117b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# CLAUDE.md

Working notes for Claude Code on this project. Read before editing.

## What this is

`sbo-batch-test`: a single self-contained bash script that batch-tests
SlackBuilds against a clean Slackware 15.0 overlay chroot. The user is an SBo
(SlackBuilds.org) maintainer on Slackware64-current who needs to verify builds
against 15.0 stable without booting a VM.

Full spec lives in `claude-code-prompt-sbo-batch-tester.txt`. Reference mount
machinery in `overlay-chroot.sh` (Jeremy Hansen / bassmadrigal). User-facing
docs in `README.md`.

## Conventions (the user cares about these)

- **No em dash character** in any prose, comments, README, or commit messages.
  Use commas or periods. This is a hard rule.
- This session runs with ponytail (laziest working solution) and caveman
  (terse replies) modes. Code stays normal; chat is terse.
- Build incrementally. The user wants to review the dep resolver and the
  mount/teardown core before trusting the rest. Do not balloon scope.
- Do NOT default to agreement. If a choice is fragile or wrong, say so and
  propose better with reasoning.

## Hard constraints (do not violate)

- **Resolution is LOCAL-tree-only.** Never add network/sbopkg resolution. The
  local SBo tree is the single source of truth (contains unpublished
  personal/pentesting packages). Settled, not open for revisiting.
- **overlay lowerdir must be LOCAL.** `SLACKWARE_BASE` is a local fs path.
  `LOCAL_MIRROR_15` is the NFS mountpoint, a package SOURCE only (content read
  via the derived `MIRROR_TREE`). overlayfs over NFS lowerdir is fragile. The
  script guards against pointing base under the mirror. The mirror fstab entry
  is `noauto`; the script checks `mountpoint -q` and auto-mounts (`mount
  $LOCAL_MIRROR_15`) if absent, left mounted after the run.
- **Do not wrap/drive slackrepo.** Separate pipeline, keep independent.
- **Shares host kernel.** No kernel-module testing claims.
- Runs as root only (overlay + chroot).
- Per-target disposable overlay: each category target tests against pristine
  15.0. Built packages are throwaway.

## Architecture (single file: sbo-batch-test)

Top-to-bottom layout:

1. **CONFIG block** - empty defaults plus a `source` of the external config
   file. Real values live OUTSIDE the script in `$SBO_BATCH_CONFIG` (default
   `~/.config/sbo-batch-tester/config`, i.e. `/root/.config/...` since it runs
   as root); `config.example` in the repo is the template. The block sets empty
   defaults (`SLACKWARE_BASE LOCAL_MIRROR_15 SBO_TREE_ROOTS`) plus
   `CHROOT_LOCATION=/tmp LOG_ROOT PKG_CACHE='' VERSION=15.0`, sources the config
   if present
   (NOT an error if missing, so the script stays sourceable by `test-logic.sh`),
   then derives `MIRROR_TREE`. `require_config` (called by `validate_env` and
   `init_base`) is what hard-fails a real run when the config is absent or has
   not set the required paths. `LOCAL_MIRROR_15` is the NFS mountpoint; the tree
   is one level down, `MIRROR_TREE="$LOCAL_MIRROR_15/slackware64-$VERSION"`
   (holds ChangeLog.txt, slackware64/, patches/). All mirror content reads use
   `MIRROR_TREE`; the mountpoint check, auto-mount, and the under-mirror guard
   use `LOCAL_MIRROR_15`.
2. **Globals / flags** - `USE_COLOR DRY_RUN WITH_X JOBS`, status maps
   (`ST_STATUS ST_REASON ST_TIME ST_README`), `ACTIVE_MOUNTS[]`.
3. **usage / init_color / parse_args / validate_env** - fail-fast startup
   checks with copy-pasteable hints.
4. **init_base** - `--init-base` mode only. First-time populate: `installpkg
   --root` the full `slackware64/*/*.t?z` set into `SLACKWARE_BASE`, seed the
   `last-base-update` marker, exit. Runs its own checks (root, mirror mounted
   /auto-mount, ChangeLog.txt present, not under mirror) since the base does not
   exist yet; refuses to clobber a populated base. Wired in `main` before
   `validate_env`, exits 0. installpkg/upgradepkg run with `--terse`.
   **update_base** - patches local base from mirror's `patches/packages/` when
   ChangeLog head differs (reused from reference script).
5. **SBo tree lookup** - `find_slackbuild_dir`, `category_of`, `pkg_key`,
   `read_requires`.
6. **Dependency resolution** - `resolve_target` -> `_resolve_visit` (DFS topo
   sort + cycle detection). Outputs `RESOLVED_ORDER[]`, records `UNMET[]`,
   `CYCLES[]`, `HAS_README[]`. `installed_in_base` checks base package db.
7. **Overlay lifecycle** - `setup_overlay` (echoes tmpdir, mounts overlay +
   binds), `teardown_overlay` (idempotent, correct reverse order), `cleanup_trap`
   (EXIT/INT/TERM, unwinds all live overlays).
8. **build_one** - copies SlackBuild into overlay, runs download/md5/build/
   installpkg INSIDE the chroot non-interactively via heredoc, reads back a
   status token file, sets status maps. Logs resolved .info env up front and
   the installed file list (from /var/log/packages) after installpkg, so the
   overlay is fully disposable.
9. **run_target** - fresh overlay per target, builds resolved chain in order,
   marks `BLOCKED-BY-DEP` on dependents of failures, tears down.
10. **print_summary** - color screen recap + plain `summary.log`.
11. **main** - parse, validate, make `RUN_DIR`, update base, collect targets
    (single-package or category-folder), run each.

## Teardown order (do not reorder)

pts -> dev/proc/sys -> resolv.conf -> dbus machine-id -> overlay last.
Matches the reference script. Idempotent (mountpoint-guarded), trap-registered
so a mid-target abort still unwinds. `ACTIVE_MOUNTS[]` tracks live overlays.

## Status values

`SUCCESS CACHED DOWNLOAD-FAILED MD5-MISMATCH BUILD-FAILED INSTALL-FAILED
BLOCKED-BY-DEP UNMET-DEP`. `CACHED` = a dependency installed from the persistent
package cache instead of being rebuilt (target is never CACHED). `%README%`
recorded separately as a reminder flag, not a status.

## What is verified vs not

- **Verified by self-check** (`test-logic.sh` in repo, `bash test-logic.sh`, no
  VM needed): topo order, `%README%` recording, unmet-dep, cycle detection, and
  BLOCKED-BY-DEP propagation (`depends_on_failed`, including the transitive
  one-hop cascade), and the package-cache logic
  (`cache_decision`/`cache_path`/`cache_store`/`version_of`). The check builds a
  fake SBo tree and sources the script with
  config overridden AFTER sourcing (sourcing re-runs the CONFIG block, which
  resets the vars to empty defaults and may source the external config, so test
  vars must be set after the `source`). The test runs as a normal user, so
  `~/.config/sbo-batch-tester/config` usually does not exist and is not sourced;
  even if it did, the post-source overrides win. Gotchas baked in: do not name the dead
  list `failed` (collides with `depends_on_failed`'s `local -n failed`), and
  `ok`/`bad` must `return 0` (`((x++))` returns nonzero when x was 0).
- **Verified on the build system**: `--init-base` populate ran clean against
  the real mirror (mountpoint check, auto-mount of the noauto NFS entry,
  `MIRROR_TREE` derivation, external config sourcing, full installpkg --terse
  set). The external-config split (`require_config`, missing/incomplete errors)
  was checked in isolation too. The full build flow ran end to end on a real
  target (`feh` + its dep `imlib2`): overlay mount, chroot build, forced
  `OUTPUT=/sbo-work/output`, per-package installpkg, teardown, summary, and
  persistent logs. The package cache was verified live: a first run populated
  `$PKG_CACHE/<cat>/<prog>/` with one .txz per prog, a re-run installed the
  cached dep (status `CACHED`, ~1s vs ~27s build) while the target rebuilt
  fresh, and the cached/build-new/target labels and the cached count rendered
  correctly. `update_base` reported "Base is up-to-date" (no patch pending), so
  patching and the on-patch cache wipe ran their up-to-date branch only.
- **NOT runnable-tested** (no occasion yet): an actual base patch via
  `update_base` (mirror was up-to-date) and therefore the on-patch cache wipe
  firing, and the `bump: OLD -> NEW` eviction path on a real version change
  (covered by the self-check, not yet seen on hardware). Logic mirrors the
  reference script.

## Known shortcuts (ponytail: comments in source)

- `depends_on_failed`: direct-REQUIRES check only. Transitive blocking still
  works because the loop runs in topo order, so a failure propagates one hop per
  package.

## Open items / TODO

- **`--keep` removed (resolved).** No keep-overlay option. Overlay is always
  torn down. Rationale: per-package logs now capture full build/install output,
  resolved `.info` env, and the installed file list, so the overlay holds
  nothing worth retaining. Do not re-add `--keep` without a reason logs cannot
  cover.
- **Package cache (DONE).** Persistent `$PKG_CACHE` (config var, empty =
  disabled), SBo-tree layout `<cat>/<prog>/<prog>-<ver>-...txz`, one .txz per
  prog. Key = prog+version (build/arch/tag ignored). The named target always
  builds fresh and refreshes the cache; deps install from cache on a version
  match (status `CACHED`), else build and cache. Cache wiped when `update_base`
  patches. Pure `cache_decision`/`cache_path`/`cache_store`/`version_of` covered
  by `test-logic.sh`. Spec: docs/superpowers/specs/2026-06-24-package-cache-design.md.
- **"all" mode**: build every package across all SBo roots. Extension point in
  `main` where `targets` is populated. TODO marker in source.
- **queue/list-file mode**: build a named list. Same extension point.
- **`-j` parallelism**: flag parsed, currently no-op. TODO marker in source.

## How to run the self-check

```sh
bash test-logic.sh
```

Covers resolution + BLOCKED-BY-DEP. Extend it (not /tmp scratch files) when
adding logic. Anything VM-dependent (overlay, chroot, installpkg) is out of its
reach by design.