109700b94987ddaa5da05d68f58fce5669765248
23
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9c75e74ea3 |
fix(ci): give the builder image what linuxdeploy needs for the AppImage
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 15m52s
🏗️ Build and Test JellyTau / Supply Chain (push) Failing after 29s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m35s
Traceability Validation / Check Requirement Traces (push) Successful in 11s
Build & Release / Run Tests (push) Successful in 14m53s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m22s
Build & Release / Build Linux (push) Successful in 20m53s
Build & Release / Build Windows (push) Successful in 15m41s
Build & Release / Build Android (push) Successful in 30m46s
Build & Release / Create Release (push) Successful in 38s
The v0.10.0 release build failed in Build Linux after 16 minutes: failed to bundle project: xdg-open binary not found /usr/bin/xdg-open: No such file or directory linuxdeploy embeds xdg-open into the AppImage and aborts the whole bundle when it is absent. deb and rpm had already bundled fine; only AppImage was affected. This is the one failure tonight that building locally could not have caught, and the reason is worth writing down: a developer machine is a desktop and always has xdg-utils, so the AppImage builds there and fails on a minimal server image. The asymmetry is the bug. Every other release defect this evening was found by building locally first; this one needed the runner. xdg-utils, desktop-file-utils and zsync are added together rather than one at a time. Each round trip costs an image rebuild plus a failed release build, and those three are what linuxdeploy commonly reaches for (xdg-open, desktop-file-validate, and zsync for delta updates). Workflows move to jellytau-builder:2026.08.1, built and pushed with all three verified present inside it before this commit. ci-operations.md gains two things learned here: that an apt addition invalidates the layer above the cargo-install steps, so it is a ~20 minute rebuild rather than the ~2 minutes the trailing layer normally gives; and that Tauri's AppImage bundler downloads linuxdeploy, AppRun and two plugin scripts from GitHub during the build, so an AppImage build depends on GitHub being reachable from the runner. |
||
|
|
76a2d9609b |
fix(release): produce updater artifacts, and point the manifest at them
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 15m32s
🏗️ Build and Test JellyTau / Supply Chain (push) Failing after 29s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m34s
Traceability Validation / Check Requirement Traces (push) Successful in 11s
Build & Release / Run Tests (push) Successful in 14m49s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m22s
Build & Release / Build Linux (push) Failing after 17m42s
Build & Release / Build Windows (push) Successful in 15m46s
Build & Release / Build Android (push) Successful in 30m54s
Build & Release / Create Release (push) Skipped
Two defects on the release path, both of which would have failed the v0.10.0 build after all three platforms had already compiled -- caught by running a real signed build locally instead of waiting for the tag. **createUpdaterArtifacts was never set.** Without it Tauri emits only the plain .AppImage and .exe: no signatures at all. The manifest step then finds none and aborts by design, so the release dies at Create Release having spent ~40 minutes building artifacts it cannot publish. **The manifest looked for the wrong filename.** Tauri v2 signs the .AppImage *itself* and writes <name>.AppImage.sig beside it. The .AppImage.tar.gz form this workflow globbed for only exists under createUpdaterArtifacts: "v1Compatible". A real signed build produced: 154M JellyTau_0.10.0_amd64.AppImage 420 JellyTau_0.10.0_amd64.AppImage.sig so the glob would have matched nothing and the step would have aborted for a second, entirely different reason. Both the artifact collection and the manifest now use the v2 names, and the AppImage and its .sig ship together -- a manifest referencing a signature that was never uploaded fails only on the user's machine. Verified before tagging rather than after: the manifest logic was run against the real artifacts (420-char minisign signature read correctly) and the resulting latest.json checked for validity and shape. The Windows side already used the correct pattern (<installer>.exe.sig), which is why only Linux needed the change. |
||
|
|
214997144f |
feat(deps): upgrade Tauri to 2.11.5, and own the Android context it stopped setting
🏗️ Build and Test JellyTau / Run Tests (pull_request) Successful in 22m51s
🏗️ Build and Test JellyTau / Supply Chain (pull_request) Failing after 25s
Traceability Validation / Check Requirement Traces (pull_request) Successful in 14s
🏗️ Build and Test JellyTau / Android Compile Check (pull_request) Successful in 4m19s
The plugin versions could not be matched upward without this: both
tauri-plugin-log 2.9.0 and tauri-plugin-updater 2.10.1 require tauri
^2.10, and the tree was on 2.9.5. So the framework moves with them --
tauri 2.9.5 -> 2.11.5, tauri-build 2.5.3 -> 2.6.3, wry 0.53.5 -> 0.55.1
-- and every plugin's Rust crate and npm package is now pinned to the
same version on both sides.
That upgrade broke Android outright, and the breakage is the interesting
part.
Seven call sites in this crate reach JNI through
ndk_context::android_context(), which reads a process-global pair of
pointers. Nothing here ever set that global. `tao` did -- the windowing
layer under wry, three levels below anything this project names in
Cargo.toml. tao 0.34.5 called initialize_android_context() while starting
the activity and our code read what it left behind. tao 0.35.3 keeps the
same two pointers in a private struct and no longer publishes them.
The result, on every launch, was:
PANIC at ndk-context/src/lib.rs:72: android context was not initialized
8: ndk_context::android_context
9: jellytau_lib::run::{{closure}}
Not a crash in our code, and not a change to our code: an undocumented
side effect of a transitive dependency disappeared. Relying on someone
else to populate a global is a dependency that does not appear in
Cargo.toml and gives no warning when it goes.
src-tauri/src/android_context.rs now owns that invariant instead of
assuming it. JNI_OnLoad captures the JavaVM as the shared library loads
-- the earliest moment available, and nothing in tao, wry or tauri
defines one to collide with. The Context is resolved lazily via
ActivityThread.currentApplication() and pinned as a global reference for
the process lifetime, since ndk_context stores a bare pointer and does
not own it. It publishes the Application rather than the Activity:
SecureStorage.initialize() immediately reduces its argument to
applicationContext anyway, and an Application cannot outlive itself the
way a retained Activity would.
Restoring the global keeps all seven callers untouched. Threading a VM
and Context handle through five credential call sites would have been a
larger change with more risk, on the credential path.
Failure now degrades instead of aborting: it is logged and credentials
fall back to the encrypted-file path, which the app already supports.
Verified on a device, R8-minified, not merely compiled:
[INIT] Android JavaVM and Application published to ndk_context
Android SecureStorage initialized successfully
Android Keystore available via SecureStorage
[INIT] Using system keyring for credential storage
[CodecDetection] Detected 7 video codecs: av1,h263,h264,hevc,...
-- the real keystore path, not the fallback, and the app stays up. None
of this is reachable by CI: nothing there runs the app.
Also fixed here, both found the same way:
- `tauri android build --apk true` is now `--apk`. The CLI took a value
until 2.10; from 2.11 the stray `true` is a positional and the build
fails before starting. Three call sites in build-android.sh and one
in build-release.yml -- the latter builds the signed APK, by far the
most-downloaded artifact.
- scripts/build-android.sh ran `npm install` on its clean-build path in
a bun project, ignoring bun.lock and re-resolving the tree. That is
exactly how the plugin crate/package versions drift apart again.
scripts/check-tooling.sh now fails on any npm/yarn/pnpm invocation or
foreign lockfile, and runs in CI.
DR-222, DR-223.
|
||
|
|
9a19d30e6c |
fix(build): make the release actually buildable, and check it before tagging
🏗️ Build and Test JellyTau / Run Tests (pull_request) Successful in 18m41s
🏗️ Build and Test JellyTau / Supply Chain (pull_request) Successful in 31s
Traceability Validation / Check Requirement Traces (pull_request) Successful in 9s
🏗️ Build and Test JellyTau / Android Compile Check (pull_request) Successful in 4m5s
Preparing v0.10.0 meant building the release locally first. It did not build. Two separate defects were sitting on master, both invisible to every gate this project has, for the same reason: nothing in build-and-test.yml runs `tauri build`. Only a tag does. So the first time anyone would have discovered either was a failed release. **Tauri plugin versions had drifted apart.** Tauri refuses to build when a plugin's Rust crate and npm package are on different minor versions: tauri-plugin-log (v2.8.0) : @tauri-apps/plugin-log (v2.9.0) tauri-plugin-updater (v2.9.0) : @tauri-apps/plugin-updater (v2.10.1) Introduced by the updater and diagnostics work in this same branch -- `cargo add` took what the pinned toolchain allowed while `bun add` took latest, and the caret ranges let them separate. cargo check, clippy, cargo test and svelte-check all passed. Matching upward pulled wry 0.53.5 -> 0.54.2 along with wasm-bindgen, web-sys and webkit2gtk: the webview layer, which on Linux is the video playback path. That is not a change to make while cutting a release, so the npm packages are pinned down to the crates instead -- exactly, not by caret, since the caret is what allowed the drift. The upgrade is worth doing deliberately, with a playback check, and ci-operations.md says so. CI now runs `tauri info`, which performs the same comparison without building. Verified by reintroducing the mismatch and watching it fail. **The AppImage target had never been built.** It was added earlier in this branch because the release notes had advertised an AppImage for months while tauri.conf.json never produced one. It does not work out of the box: linuxdeploy carries its own `strip`, too old to parse the .relr.dyn section modern toolchains emit, and it fails on every bundled library -- strip: libzstd.so.1: unknown type [0x13] section `.relr.dyn' failed to bundle project `failed to run linuxdeploy` Ubuntu 23.10+ links with -z pack-relative-relocs by default, so the CI builder image fails exactly as a modern Arch host does. NO_STRIP=true is linuxdeploy's documented escape hatch. The resulting 153 MB AppImage was verified to be well-formed and to actually start. Without this the release would have failed at the Linux build step -- the artifact check added earlier refuses to publish when no AppImage is produced, which is the behaviour we want, but it would have refused a tagged build rather than a local one. Also: the traceability extractor now reads the tooling shell scripts that carry TRACES comments. DR-207, DR-213 and DR-220 all had them and were counted as uncovered because only .ts/.svelte/.rs were scanned. Listed individually rather than globbing scripts/*.sh -- most implement nothing, and adding one should be a decision. DR-221. |
||
|
|
5d02628689 |
fix(release): publish real notes, and stop shipping old releases' installers
🏗️ Build and Test JellyTau / Run Tests (pull_request) Successful in 15m1s
🏗️ Build and Test JellyTau / Supply Chain (pull_request) Successful in 42s
Traceability Validation / Check Requirement Traces (pull_request) Successful in 10s
🏗️ Build and Test JellyTau / Android Compile Check (pull_request) Successful in 4m6s
Two defects found while preparing v0.9.2, both of which had been shipping for months without anything to notice them by. **Every release note was the same 1,050 bytes.** All 35 releases from v0.0.1 to v0.9.1 published identical generic install instructions whose "What's New" section read "See CHANGELOG.md" -- a link that does not resolve from a release page. A reader learned nothing about what changed in any release the project has ever made. The body now comes from the `## <version>` section of CHANGELOG.md, and a missing section fails the release: notes that say nothing are worse than a build that waits for a maintainer to write two sentences. The 35 published bodies have been backfilled from the changelog via the tea CLI. This also corrects something introduced two commits ago. That change generated the body from `bun run release:notes`, which CLAUDE.md is explicit about -- its output is "a reviewed draft, not a final changelog". Publishing it unreviewed proved the point immediately: the v0.9.1..HEAD range contains a repo-wide prettier sweep, so every file in src/ counted as changed, their TRACES resolved to nearly the whole matrix, and the draft claimed the release had added the entire application. The script now skips cosmetic commits (chore(format), chore(deps), style) and reports how many rather than silently returning a smaller set, but it stays a local drafting tool. **Every release from v0.1.0 to v0.8.2 shipped every Windows installer ever built.** src-tauri/target/*/release/bundle/ is not versioned, cargo never cleans it, and the runner reuses the target directory -- so the copy step's bundle/**/*-setup.exe glob collected the lot. v0.8.2 carried sixteen installers, thirteen of them stale; v0.5.0 offered users a download list going back to 0.1.0. Eight months, and nothing to notice it by: the upload loop reported success, the files were real, and the page looked busy rather than wrong. It stopped only because an unrelated cargo cache change wiped the runner's target dir, so it was dormant, not fixed. Both desktop builds now remove the bundle directory before building, so a stale file cannot exist to be copied. Filtering the copy by version would have hidden it instead. The Linux job gets the same treatment: it was never hit only because Linux packaging is newer, and the glob is identical. scripts/check-release-artifacts.sh is the backstop for whatever reintroduces one by a route nobody predicted. It runs before the SBOM, the checksums and the upload -- all of which describe the file set, so a stale artifact has to be caught before it is hashed and published as part of the release. Verified against a reconstruction of the real v0.8.2 accumulation. DR-219, DR-220, UT-210. |
||
|
|
3211c96ecf |
feat(updater): in-app update on desktop, releases link on Android
Anyone who installed an AppImage or ran the Windows installer was frozen
on that version forever. Nothing in the app ever mentioned a new release
existed, and the release notes were the only announcement.
Desktop now checks a signed manifest, shows the version and its notes in
Settings, and installs and relaunches on request. The signature check is
the whole point: it is what stops a substituted download from being
installed by the app itself. Windows binaries stay unsigned for
SmartScreen purposes -- that is a code-signing certificate, a separate
problem -- but the update payload is verified against our own key.
Android is deliberately not wired to the updater. An app may not replace
its own APK; that is the package installer's job, and the plugin has no
Android implementation. It gets a link to the releases page instead of a
button that would throw.
The plugins are gated with a target-triple cfg rather than
cfg(desktop). Cargo only evaluates target cfgs in a [target.'cfg(..)']
table, so cfg(desktop) matches nothing, silently drops the dependency,
and fails much later with "Permission updater:default not found" -- which
is exactly what the first attempt here did.
Where the manifest lives took some finding. This Gitea serves
/releases/download/<tag>/<asset> but 404s on
/releases/latest/download/<asset> (verified against a real asset), so
there is no stable latest-release URL. The gitea-pages branch is
force-pushed wholesale by publish-docs.yml, so it cannot host the file
either. latest.json therefore gets its own orphan branch, read over the
raw-file URL, and is published from a scratch repo in RUNNER_TEMP rather
than by switching branches in the checkout -- doing that would have left
the following steps standing on a one-commit history, and the next step
but one runs release:notes against the real commit range.
Also fixed, all of it release-integrity:
- "appimage" is in bundle.targets. The release notes have advertised an
AppImage for months; tauri.conf.json never built one, the artifact
step globbed for *.AppImage, found nothing, and said nothing. The
step now fails instead.
- The .AppImage.tar.gz/.sig pair and the NSIS .sig are collected. A
manifest referencing a signature that was never uploaded fails only
on the user's machine, so the manifest step also refuses to write an
entry with an empty signature.
- Release notes are generated by release:notes from the traceability
graph, which is what CLAUDE.md has asked for all along, instead of a
fixed heredoc that said "see CHANGELOG.md for detailed changes" and
linked "GitHub Issues" on a Gitea-hosted project.
- The notes tell users how to verify a download with SHA256SUMS.
Requirements UR-077 / DR-217, tests UT-208 (12 cases over the version
comparison and the platform decision, including that a pre-release does
not offer itself as an upgrade to the matching release).
Verified: 1070 frontend tests, cargo check for both the host and
aarch64-linux-android (confirming the plugins are absent there), clippy
-D warnings, svelte-check 0 errors.
|
||
|
|
f6653e6a8b |
ci(security): add a supply-chain gate, checksums and an SBOM
The project shipped signed Android builds and unsigned desktop binaries
with no vulnerability scanning of any kind. Nothing checked the ~500
crate Rust graph or the JS packages against an advisory feed, and nothing
checked that what we redistribute inside an MIT bundle permits it.
The first cargo-deny run found eight vulnerabilities and one
unsoundness -- bytes, four in rustls-webpki, time, two in quick-xml and
rand -- every one of them closed by a `cargo update` nobody had a reason
to run. That update is in this commit; 740 Rust tests and clippy
-D warnings pass on the new lockfile.
Two structural fixes matter as much as the gate itself:
- deny.toml scopes the graph to the targets we actually ship. Without
it the Apple targets pull in plist -> quick-xml and report two DoS
advisories against a crate that is in no binary we release. Ignoring
those by ID would silence them everywhere, including where they
would matter; scoping makes them correctly absent.
- libmpv is pinned by rev instead of branch = "master". A branch means
the revision is whatever Cargo.lock happens to hold and any
`cargo update` silently substitutes new upstream code -- in the one
dependency that is not from crates.io and that links a C library
into the player. The rev is the commit already locked, so this pins
current behaviour rather than changing it.
Licence findings are recorded rather than waved through. libmpv and
libmpv-sys are LGPL-2.1, satisfied here by dynamic linking against the
system library; deny.toml carries the two obligations that follow (keep
the linkage dynamic, ship libmpv's licence text with any bundle carrying
the .so). MPL-2.0 crates are file-level copyleft and fine unmodified.
Releases now publish SHA256SUMS (verified in-job with `sha256sum -c`
before upload) and a CycloneDX SBOM for both halves, so "does this
release contain <vulnerable crate>?" has an answer that is not "rebuild
the tag and re-resolve it".
Workflows pin jellytau-builder:2026.08 instead of :latest. While every
job said :latest, rebuilding the image changed what every build compiled
against, including rebuilds of old release tags.
Also folded in, because both were the same class of problem:
- publish-docs.yml downloaded mdBook from GitHub releases into
/usr/local/bin at job time -- a toolchain install in CI, which
CLAUDE.md explicitly forbids, and a hard dependency on GitHub's CDN
at publish time. It is in the builder image now.
- extract-traces.ts only ever read .ts/.svelte/.rs, so every
requirement implemented by *configuration* was invisible to the
matrix that measures it. DR-205, DR-206, DR-207 and DR-215 all carry
TRACES comments nothing read, and each counted as uncovered while
being covered. Coverage was really 90%, not 88%; MIN_THRESHOLD moves
to 89 accordingly. CI workflows stay excluded and there is a test
saying why: traceability-check.yml quotes "a TRACES: comment" beside
deliberately-undefined example IDs, which the extractor would read
as real traces and then fail its own dangling-ID check.
Supply-chain requirement is DR-216.
🔴 The builder image must be rebuilt and pushed
(scripts/build-builder-image.sh 2026.08) before this reaches master --
the workflows now name a tag and tools that do not exist in the registry
yet.
|
||
|
|
d095e1f410 |
fix(ci): drop the bash-only shopt from the Linux artifact step
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 13m55s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m22s
Traceability Validation / Check Requirement Traces (push) Successful in 16s
Build & Release / Run Tests (push) Successful in 14m0s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m9s
Build & Release / Build Linux (push) Successful in 16m39s
Build & Release / Build Windows (push) Successful in 20m42s
Build & Release / Build Android (push) Successful in 29m18s
Build & Release / Create Release (push) Successful in 13s
"Prepare Linux artifacts" ran `shopt -s nullglob`, but the runner executes
`run:` blocks with POSIX sh, where shopt does not exist. It exited 127 and
failed the step -- so build-linux never uploaded, create-release (which
needs all three build jobs) never ran, and v0.9.0 and v0.9.1 both compiled
successfully but published nothing. The last release with assets is v0.8.2.
Reproduced under busybox sh: the current block prints "shopt: not found",
passes the unmatched rpm glob through literally ("cp: can't stat
'.../bundle/rpm/*.rpm'"), and exits 127. Without nullglob an unmatched
pattern stays literal, so test each candidate with [ -e ] instead; the
same input then exits 0 with the AppImage and deb copied.
traceability-check.yml already carries this rule in two places (`case`
instead of `[[ == ]]`, a pipe instead of a here-string). Keeping the fix
POSIX rather than adding `shell: bash` follows that convention and drops
the dependency on bash being present in the builder image.
|
||
|
|
a7365b9511 |
fix(ci): cache the cargo registry, not the 16 GB target dir
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 20m10s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m17s
Traceability Validation / Check Requirement Traces (push) Successful in 15s
Build & Release / Run Tests (push) Successful in 13m59s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m13s
Build & Release / Build Linux (push) Failing after 16m29s
Build & Release / Build Android (push) Canceled after 0s
Build & Release / Create Release (push) Canceled after 0s
Build & Release / Build Windows (push) Canceled after 11m6s
The runner's 74 GB disk kept filling. Measured on the box: 24 GB of
act cache, 23.18 GB of it created in 20 days -- ~1.15 GB/day against a
30-day-unused / 90-day-used GC, so it could never converge.
Cause: src-tauri/target (16 GB locally: 9.6G debug, 3.2G release, 2.4G
android) was cached under five separate keys, all keyed on
hashFiles('**/Cargo.lock'). The release script stamps the version into
Cargo.lock, so all five invalidated on every chore(release) -- 32
distinct lockfile revisions in three months.
- Cache only registry/index, registry/cache and git/db. registry/src is
omitted as well: cargo re-extracts it from the 155 MB of .crate
tarballs rather than storing 1.1 GB extracted.
- Collapse the five per-job keys into one shared cargo-registry key.
They existed to keep debug/release target artifacts from clobbering
each other; with target uncached, registry contents are
target-independent and every job wants the same crates.
- Split cargo-xwin into its own key. It tracks the xwin version in the
builder image, not our lockfile, so keying it on Cargo.lock was
re-downloading the whole Windows SDK on every release bump.
- CARGO_INCREMENTAL=0: never reused across runs, 3.5 GB of the debug dir.
- Installer artifact retention 30d -> 7d; tagged releases carry the
binaries anyway.
Inflow drops from ~5 GB to ~150 MB per lockfile change. Tradeoff: Rust
jobs now compile cold every run (~31min vs ~9min on a cache hit for the
Linux release build). Most runs already paid that, since a release bump
invalidated every key. sccache with a hard size cap is the way back if
it bites.
|
||
|
|
8fbf4d92cb |
ci: match release bundles by extension, and ship the rpm
Renaming the app to JellyTau renamed its bundles, and the release job globbed `bundle/deb/jellytau_*.deb`. The copy was wrapped in `if [ -f ... ]`, so the rename would have dropped the .deb from the release silently — a green build producing an incomplete release. Matching by extension removes the coupling between the product name and the pipeline, and an empty dist/linux now fails the job instead of passing quietly. That `if [ -f "dir/"*.ext ]` guard was also wrong on its own terms: with more than one match, test gets extra arguments and returns false. Found while verifying the rename: the rpm has been built by every release since deb+rpm became the bundle targets, and never copied, published or documented. It ships now. Also declares the package rename. Tauri kebab-cases productName into the Debian package name, so "JellyTau" produces `jelly-tau` — a different package from the `jellytau` earlier releases installed, which would have put a second copy alongside the old one. deb now declares Replaces/Conflicts/Provides and rpm Obsoletes/Provides, verified in the built control file. TRACES: | DR-214 |
||
|
|
51d914777a |
ci: fix cache-key collisions and skip duplicate release-commit test run
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 28m26s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m36s
Traceability Validation / Check Requirement Traces (push) Successful in 26s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 2m41s
The test job and build-linux shared one cargo cache key; the test job's debug artifacts claimed it first and actions/cache skips saving on an exact-key hit, so Linux release builds compiled cold every time (~31min vs ~9min for the correctly-keyed Windows job). Same collision between android-check and build-android. Give the release jobs their own keys. Also skip build-and-test.yml for chore(release) commits: the tag push triggers build-release.yml on the same commit, which runs the identical test suite, and the two ~1h workflows contended for the single runner slot. |
||
|
|
b9dab56379 |
ci: enforce the checks the contributor rules already required
Four gates that were documented but unenforced, plus the flaky test that made a full-suite run untrustworthy. Rust lint/format: CLAUDE.md has required `cargo fmt` and `cargo clippy` before every commit for as long as the rule existed, yet neither ran anywhere in CI — the requirement rested on memory alone. Both now run in build-and-test.yml and build-release.yml. rustfmt and clippy are already baked into the builder image, so nothing is installed at job time. `cargo fmt --all -- --check` is strict immediately (the tree is clean). Clippy is advisory for now: ~51 pre-existing warnings mean `-D warnings` would fail on unrelated work, so the step carries a TODO to flip the flag once the backlog clears. A compile error still fails it, so it is not a no-op. Traceability threshold: MIN_THRESHOLD sat at 50 while real coverage was 86%, so nearly half the matrix could rot before the gate objected. Ratcheted to 82 with the policy written down — it only ever goes up, and is never lowered to make a red build pass. The same figure lives in MIN_COVERAGE_PERCENT so `traces:coverage` gates locally on the same bar, and a test fails if the two drift. Dangling IDs: a TRACES comment could name any well-formed ID and the extractor accepted it silently, so typos and renames that missed a call site passed unnoticed. `bun run traces:validate` cross-checks every traced ID against the table rows in requirements.md and fails with the referencing files listed. It spans UT/IT as well, which the coverage orphan list ignores by design. This currently reports DR-189 and UT-188, which are being defined separately. Flaky offlineCatalog test: the first dynamic import of the service paid ~1s to transform its dependency graph, charged to a test body against vitest's 5s default. Alone it passed; under suite-wide contention it timed out. The import is now warmed at collection time, so no test is timing the compiler — the timeout is deliberately unchanged. The store shim also drops subscribers from module instances discarded by resetModules, which previously leaked across tests. |
||
|
|
3619f71aba |
build: make the git tag the single source of truth for the version (DR-153)
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 6m55s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m21s
Traceability Validation / Check Requirement Traces (push) Successful in 15s
Build & Release / Run Tests (push) Successful in 7m36s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 2m57s
Build & Release / Build Linux (push) Successful in 20m4s
Build & Release / Build Windows (push) Successful in 8m42s
Build & Release / Build Android (push) Successful in 30m30s
Build & Release / Create Release (push) Successful in 17s
The version lived in four files — package.json, tauri.conf.json, Cargo.toml and
Cargo.lock — that had to be hand-edited in lockstep, and the release workflow
rewrote exactly one of them. A tagged build therefore produced an installer
named for the tag wrapped around package metadata naming the previous release,
and the Linux job, which had no version step at all, shipped whatever happened
to be committed.
scripts/set-version.sh now writes all four from one argument and is the only
thing that does. Every release job calls it with the tag, including the Linux
job that was missing one. The committed versions become a placeholder for dev
builds rather than something to maintain by hand.
The Android versionCode moves into the same script, unchanged in formula
(1000 + major*10000 + minor*100 + patch). It stays inline-documented because the
reasoning is not obvious: builds already in the field shipped code 1000, and
Android refuses an update whose code is lower than the installed one, so a
formula that can emit a smaller number for a newer release bricks updates
irreversibly. UT-150 asserts that property directly — monotonic across an
upgrade sequence, and always above the floor.
Two edge cases the previous inline version got wrong:
- A prerelease tag (v0.6.0-rc1) made $(( 0-rc1 )) abort the step under set -e.
The suffix is stripped before the arithmetic; the manifests keep it.
- CI passes "${GITHUB_REF#refs/tags/}" unconditionally, which on a branch build
is still a full ref. That reached the validator verbatim and would have failed
every untagged Android build; a non-tag ref now falls back to git describe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
c3ead64748 |
ci(release): build Windows NSIS installer on tag
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 18m37s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m13s
Traceability Validation / Check Requirement Traces (push) Successful in 17s
Build & Release / Run Tests (push) Successful in 4m48s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m36s
Build & Release / Build Linux (push) Successful in 17m58s
Build & Release / Build Windows (push) Successful in 22m16s
Build & Release / Build Android (push) Successful in 29m7s
Build & Release / Create Release (push) Successful in 15s
Adds a build-windows job to the release workflow, cross-compiling the Windows NSIS installer from Linux via the builder image (MSVC target + cargo-xwin, no toolchain installs). Wires its artifacts into create-release alongside Linux and Android. TRACES: UR-003 | DR-004 |
||
|
|
7b8a8f66e5 |
CI: make versionCode step POSIX sh compatible
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 4m24s
Traceability Validation / Check Requirement Traces (push) Successful in 24s
Build & Release / Run Tests (push) Successful in 5m24s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m31s
Build & Release / Build Linux (push) Successful in 17m40s
Build & Release / Build Android (push) Successful in 22m33s
Build & Release / Create Release (push) Successful in 14s
The runner executes workflow steps with /bin/sh (dash), which has no here-strings: `IFS='.' read -r MAJ MIN PAT <<< "$VERSION"` failed with "Syntax error: redirection unexpected" and aborted the Android release build. Parse the semver with `cut` instead, drop the GNU-only `\s` from the sed expression in favour of [[:space:]], and default any missing component to 0 so a malformed version can never emit versionCode 0. Verified under sh: 0.0.14 -> 1014, 0.0.15 -> 1015, 0.1.0 -> 1100, 1.0.0 -> 11000 (monotonic). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
2e479d05b3 |
Navigation up/back split, faster startup, and CI versionCode fix
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 4m57s
Traceability Validation / Check Requirement Traces (push) Successful in 22s
Build & Release / Run Tests (push) Successful in 5m13s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m30s
Build & Release / Build Linux (push) Successful in 17m52s
Build & Release / Build Android (push) Failing after 58s
Build & Release / Create Release (push) Has been skipped
Navigation: - Split conflated "back" into navigateUp (deterministic route parent) and a history-safe navigateBack that tracks in-app depth via afterNavigate instead of history.length. Fixes the resume-from-background trap where a stale WebView stack left the header arrow stuck on the current page. - /library self-corrects for music/tv/movies (which have dedicated landing pages): a leftover currentLibrary no longer forces the inline content-list view, so "up"/back shows the libraries overview. Live TV / channels / other types still render inline. Startup (unblock first paint): - auth.initialize() no longer awaits security-status, player-config, or session verification before flipping isInitialized. These run fire-and-forget after the session is restored, so the library overview paints without waiting on several serial IPC round-trips. Versioning / CI: - tauri.conf.json + package.json aligned to 0.0.15 (the tag series had drifted to 0.1.0, whose formula-derived versionCode 1000 outran the v0.0.x tags). - Release workflow now pins a monotonic Android versionCode (1000 + major*10000 + minor*100 + patch) so tagged builds never downgrade below prior installs and always increase in semver order. Tests: navigation (4), auth (29), playbackMode (23) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
674c8e5cd0 |
ci(release): fix release-notes generation breaking jq publish step
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 3m11s
Traceability Validation / Check Requirement Traces (push) Successful in 20s
Build & Release / Run Tests (push) Successful in 3m40s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 18m36s
Build & Release / Build Linux (push) Successful in 15m56s
Build & Release / Build Android (push) Successful in 18m33s
Build & Release / Create Release (push) Successful in 7s
The release-notes echo lines used unescaped backticks, which the shell ran as command substitution; their output leaked control characters into release_notes.md, so jq failed with 'Invalid string: control characters ... must be escaped' when building the release payload. - Escape the backticks so they are literal markdown. - Remove emoji from the release-notes content (plain ASCII headings). - Handle an already-existing release (HTTP 409) by reusing its id for asset upload instead of failing. |
||
|
|
7fb866a583 |
ci: fix release Android build --apk flag requires explicit value
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 2m26s
Traceability Validation / Check Requirement Traces (push) Successful in 19s
Build & Release / Run Tests (push) Successful in 2m29s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 17m57s
Build & Release / Build Linux (push) Successful in 15m38s
Build & Release / Build Android (push) Failing after 14m48s
Build & Release / Create Release (push) Has been skipped
Tauri CLI requires '--apk true'; bare '--apk' fails with "a value is required for '--apk <APK>'". The release workflow only reached this step now that checkout/container issues are fixed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
0c3ed74fe1 |
ci: Improvements
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 12m47s
Traceability Validation / Check Requirement Traces (push) Successful in 22s
Build & Release / Run Tests (push) Successful in 2m27s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 28m0s
Build & Release / Build Linux (push) Successful in 15m45s
Build & Release / Build Android (push) Failing after 49s
Build & Release / Create Release (push) Has been skipped
|
||
|
|
26286ac6e7 | sign build | ||
|
|
8f1c4bc9da | correct CI tag | ||
|
|
e664bf4620 | added tests, use specific CI | ||
|
|
e3797f32ca | many changes |