Fixed
-
make check-dev-commandsnow understands release-swapped trees. The
second latent release-tree gate failure (after the fuzz-ref-pin one): the
checker demanded every-devcommand twin, which the release prod-swap
legitimately deletes, solintfailed on every release PR. The checker
now reads the plugin manifest's name to learn the tree state — dev tree
(z-spec-dev): twins present and in sync; prod tree (z-spec): zero
twins allowed, a leftover twin is real drift; any other name fails loud.
All five states covered by a new regression test. -
Release PRs can pass the all-legs CI gate again. Two structural
failures surfaced the first time a release ran under the required-legs
regime:tests/test_fuzz_ref_pin.pyhard-listed the generated-dev
command twins, which the release prod-swap legitimately deletes (it now
discovers pin sites dynamically, requires the prod trio, and enforces
exactly one full 40-hex pin per file); and theinstallerCI legs tried
to install the release's bumped version from PyPI before the tag
publishes it (install.sh gained aZSPEC_LOCAL_WHEELenv seam, and CI
builds the wheel from the tree under review onrelease/*PRs — same
script, only the CLI's download source swapped). -
z-spec's lux menu entries now merge into the same Clients submenu as the
session's other applets. The applet name stamped the MCP server's own
process pid; luxd groups Clients-menu entries by the session pid parsed
from the name, so z-spec always landed in its own orphan submenu (a
separate "repo (N)" entry per session) instead of joining vox-panel's.
The name now carries the Claude session pid (the server's parent),
matching vox-panel. Restart or reconnect z-spec MCP servers to pick the
fix up. Reported by the lux agent with a precise cross-repo diagnosis. -
CI now proves the software itself — not just the installer — on every
supported OS.unit,e2e, andspecsare matrixed over Ubuntu and
macOS (previously Ubuntu-only; the test suite had never run on macOS).
specsdownloads the per-OS probcli archive (ProB.macos.zip/
ProB.linux64.tar.gz) and builds fuzz with per-OS prerequisites. -
The installer matrix gained a TeX dimension (
tex: absent | present,
4 legs).tex=presentinstalls a real TeX distribution (texlive-base /
BasicTeX) before runninginstall.shand then requires
kpsewhich fuzz.styto succeed — the first CI proof of the
TEXMFHOMEcopy +mktexlsrchain, which a bare runner can never
exercise.tex=absentkeeps proving the no-TeX path degrades gracefully. -
CI's
specsjob now buildsfuzzviainstall.sh's owninstall_fuzz(),
not a second, separate build script. The sudo-free installer shipped in
v0.20.4 had never been exercised by CI or on a genuinely clean machine —
thespecsjob builtfuzzwith its own inline./configure && make && sudo make install, unrelated to and untested against the new sudo-free
path. Addedinstall.sh --fuzz-only(build and installfuzzonly, no
CLI/probcli/plugin steps) and pointed CI at it, so a regression in the
sudo-free build now fails thespecsjob instead of going unnoticed.
Verified locally by removing the installedfuzzbinary and re-running
install.sh --fuzz-onlyfrom a genuinely clean state — realgit clone,
configure --prefix,make,make install, andTEXMFHOMEcopy, no sudo,
no privilege prompt. Also verified against the exact v0.20.4-tagged
install.sh(before this fix), run end to end as a realcurl | shuser
would — CLI, probcli, and a genuine fresh sudo-freefuzzbuild all
succeeded from a clean state. -
CI now runs the whole installer on both Ubuntu and macOS. A new
installermatrix job runsinstall.sh --no-pluginend to end on each
OS — the CLI viauv tool install, probcli via its per-OS archive, and
the sudo-freefuzzsource build — then verifies through the installed
artifact itself:z-spec doctor, a real type-check, and a real
model-check. The installer previously had zero automated coverage on
macOS, the other platform this repo claims to support.