That's AB's known-broken Xcode CLT (SwiftBridging modulemap redefinition; swiftc --version answers but real compiles die — documented since the September install work). AB has never compiled this tool: its binary was always built on the MacBook (or shipped inside the .app, which build.sh compiles at -target arm64-apple-macos13.0) — and the catalog update deletes the module folder, binary included. So "update Timers" was guaranteed to kill LTC on that machine, self-build or not.
Fix
installModule now carries executables (any execute bit) the download does not include over from the copy being replaced — or from the app's bundled copy on a first install — preserving relative path and mode. Executables only, deliberately: those are the gitignored per-machine build artifacts (ltc-capture, spl-capture), while stray text files from an old version — code an update deliberately removed — must not be resurrected. The Timers module's staleness check still notices a carried binary older than its updated source and rebuilds behind it on machines whose toolchain works (NA), while a machine that can't build (AB) keeps the working binary.
Verified
End-to-end against the real Gitea catalog in a scratch server root + data dir: an installed 1.4.9 copy holding a fake executable ltc-capture and a stray old-code.js, then POST /api/admin/modules/propresenter-timers/install → real 1.5.0 download. Afterwards: the executable survives with mode and content intact (fake-per-machine-binary still runs), the stray file is gone, and the log says module update kept per-machine executable "ltc-capture".
Shell 1.9.1 → 1.9.2. AB's immediate fix is separate (an arm64/macos13-target ltc-capture compiled on the MacBook, staged and ready to copy over — the module's 30 s retry picks it up with no restart); this PR makes sure the next update doesn't undo it.
## Why AB's build "keeps failing"
With shell 1.9.1 running, AB's restart correctly activated Timers 1.5.0 and the self-build ran — and failed, every retry, with:
```
ltc-capture build failed (exit 1): /Library/Developer/CommandLineTools/usr/include/swift/bridging.modulemap: 0:
```
That's AB's **known-broken Xcode CLT** (SwiftBridging modulemap redefinition; `swiftc --version` answers but real compiles die — documented since the September install work). AB has never compiled this tool: its binary was always built on the MacBook (or shipped inside the .app, which `build.sh` compiles at `-target arm64-apple-macos13.0`) — and the catalog update **deletes the module folder**, binary included. So "update Timers" was guaranteed to kill LTC on that machine, self-build or not.
## Fix
`installModule` now carries **executables** (any execute bit) the download does not include over from the copy being replaced — or from the app's bundled copy on a first install — preserving relative path and mode. Executables only, deliberately: those are the gitignored per-machine build artifacts (`ltc-capture`, `spl-capture`), while stray *text* files from an old version — code an update deliberately removed — must not be resurrected. The Timers module's staleness check still notices a carried binary older than its updated source and rebuilds behind it on machines whose toolchain works (NA), while a machine that can't build (AB) keeps the working binary.
## Verified
End-to-end against the real Gitea catalog in a scratch server root + data dir: an installed 1.4.9 copy holding a fake executable `ltc-capture` and a stray `old-code.js`, then `POST /api/admin/modules/propresenter-timers/install` → real 1.5.0 download. Afterwards: the executable survives with mode and content intact (`fake-per-machine-binary` still runs), the stray file is gone, and the log says `module update kept per-machine executable "ltc-capture"`.
Shell 1.9.1 → 1.9.2. AB's immediate fix is separate (an arm64/macos13-target `ltc-capture` compiled on the MacBook, staged and ready to copy over — the module's 30 s retry picks it up with no restart); this PR makes sure the *next* update doesn't undo it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
AB updated Timers from the catalog and LTC died: the update replaces the
module folder wholesale, which deleted the compiled ltc-capture binary —
and AB's Xcode CLT cannot rebuild it (the SwiftBridging modulemap defect;
the module's new self-build correctly runs there and fails with exactly
that error). The binary on AB has always been compiled elsewhere and
shipped, so 'update' was guaranteed to break LTC on that machine.
installModule now carries executables (any execute bit) the download does
not include over from the copy being replaced — or from the app's bundled
copy on a first install — preserving path and mode. Executables only, on
purpose: those are the gitignored per-machine build artifacts (ltc-capture,
spl-capture), while stray text files from an old version — code an update
deliberately removed — must not be resurrected. The Timers module's
staleness check still notices a carried binary older than its updated
source and rebuilds behind it where the toolchain works.
Verified end-to-end against the real Gitea catalog: an installed 1.4.9
copy holding a fake executable and a stray .js file, updated to 1.5.0 —
the executable survives with its mode and content, the stray file is gone,
and the log names what was kept.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
michael
merged commit 4c6a2b8f76 into main2026-09-27 10:49:10 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why AB's build "keeps failing"
With shell 1.9.1 running, AB's restart correctly activated Timers 1.5.0 and the self-build ran — and failed, every retry, with:
That's AB's known-broken Xcode CLT (SwiftBridging modulemap redefinition;
swiftc --versionanswers but real compiles die — documented since the September install work). AB has never compiled this tool: its binary was always built on the MacBook (or shipped inside the .app, whichbuild.shcompiles at-target arm64-apple-macos13.0) — and the catalog update deletes the module folder, binary included. So "update Timers" was guaranteed to kill LTC on that machine, self-build or not.Fix
installModulenow carries executables (any execute bit) the download does not include over from the copy being replaced — or from the app's bundled copy on a first install — preserving relative path and mode. Executables only, deliberately: those are the gitignored per-machine build artifacts (ltc-capture,spl-capture), while stray text files from an old version — code an update deliberately removed — must not be resurrected. The Timers module's staleness check still notices a carried binary older than its updated source and rebuilds behind it on machines whose toolchain works (NA), while a machine that can't build (AB) keeps the working binary.Verified
End-to-end against the real Gitea catalog in a scratch server root + data dir: an installed 1.4.9 copy holding a fake executable
ltc-captureand a strayold-code.js, thenPOST /api/admin/modules/propresenter-timers/install→ real 1.5.0 download. Afterwards: the executable survives with mode and content intact (fake-per-machine-binarystill runs), the stray file is gone, and the log saysmodule update kept per-machine executable "ltc-capture".Shell 1.9.1 → 1.9.2. AB's immediate fix is separate (an arm64/macos13-target
ltc-capturecompiled on the MacBook, staged and ready to copy over — the module's 30 s retry picks it up with no restart); this PR makes sure the next update doesn't undo it.🤖 Generated with Claude Code