-
Notifications
You must be signed in to change notification settings - Fork 0
Releases: jetomev/nog
v1.0.4 — split-PKGBUILD pkgbase coupling
Hotfix — split-PKGBUILD pkgbase coupling
nog update on v1.0.3 could leave a system in a tier-mismatched lockstep deadlock when Arch's split-PKGBUILD families had their members straddle the Tier boundary. Surfaced 2026年05月25日 when pipewire and pipewire-pulse were Tier 2 held while the rest of the family (libpipewire, pipewire-audio, pipewire-alsa, pipewire-jack, gst-plugin-pipewire, alsa-card-profiles, lib32-pipewire, lib32-libpipewire) defaulted to Tier 3 Ready. pacman aborted:
:: installing libpipewire (1:1.6.5-2) breaks dependency 'libpipewire=1:1.6.5-1' required by pipewire :: installing libpipewire (1:1.6.5-2) breaks dependency 'libpipewire=1:1.6.5-1' required by pipewire-pulse
Same architectural class as v1.0.3 (*-headers coupling), broader scope.
What's new
- Layer A — pkgbase sibling coupling. Reads the
%BASE%field from pacman's sync DBs. Packages sharing apkgbaseform a coupled group; the group inherits the highest tier present in the group. Auto-handles pipewire, plasma, qt5/qt6, kde-applications, gnome — any Arch split PKGBUILD where Arch enforces lockstep via=version deps. - Layer B —
lib32-<X>auto-coupling. Multilib packages have their own pkgbase but are version-pinned to the main package by Arch convention. Strippinglib32-and inheriting the base's tier covers cases likemesa↔lib32-mesawhere pkgbase alone wouldn't bridge them. Composes with Layer A:lib32-libpipewireresolves Tier 2 via its lib32-pipewire sibling, which itself resolves via the lib32- prefix topipewire. - Layer D —
nog unlock --promoteworks for any tier. v1.0.3 restricted unlock to Tier 1. Now any package can be force-upgraded via--promoteregardless of tier, so users can manually break a lockstep deadlock if some edge case escapes the auto-coupling.
Migration notes
After upgrading, many more packages will silently re-classify to Tier 1 or Tier 2 via pkgbase coupling. Examples:
- pipewire family (
libpipewire,pipewire-audio, etc.) → Tier 2 (inheriting frompipewire) lib32-mesa,lib32-vulkan-icd-loader, etc. → Tier 1 (inheriting frommesavia lib32 prefix)plasma-metasiblings → Tier 2 (inheriting fromplasma-desktop)- qt5/qt6 sub-libraries → Tier 2 if any qt package is Tier 2
On your next nog update you'll see more packages in the Held bucket than v1.0.3 — exactly the same pattern of silent re-tiering as v1.0.3's *-headers rule, just broader scope.
Verify the fix is active
nog search libpipewire # expect: yellow [Tier 2 — 15d hold] annotation (was green Tier 3 in v1.0.3) nog search lib32-mesa # expect: red [Tier 1 — 30d hold] annotation
If you see green Tier 3, the upgrade didn't apply.
Performance note
load_tiers() now walks the sync DB once per nog invocation to build the pkgbase index. The walk is OnceLock-cached so classify calls within the same process don't re-walk. Adds a one-time hundreds-of-ms cost to commands that previously didn't touch the DB (nog install, nog search, nog pin, nog unlock). Accepted for the correctness gain.
Under the hood
- Tests: 14 → 22 (8 new in
tiers::testscovering pkgbase coupling, lib32 in all four variations, empty-index back-compat, composed Layer A + B) - TEST-MATRIX section 17: 16 new regression-guard checks across 17a (Layer A pkgbase), 17b (Layer B lib32), 17c (live family-upgrade reproduction), 17d (Layer D Tier 2 unlock), 17e (no false positives on coherent systems)
- No new dependencies; same dynamic-libzstd linking contract as v1.0.1 / v1.0.2 / v1.0.3
- v1.0.3's
*-headersrule and--realignflag both kept — pkgbase coupling supersedes the special case but the explicit rule reads more clearly and survives custom kernels with non-standard pkgbase names
Full changelog with the failure narrative: README → v1.0.4.
🤖 Generated with Claude Code
Co-developed by jetomev (idea, vision, direction, testing) and Claude (architecture, implementation).
Assets 2
v1.0.3 — kernel / headers / DKMS coupling
Hotfix — kernel / headers / DKMS coupling
nog update on v1.0.2 could leave a system in a state where its Tier 1 30-day kernel hold raced against a Tier 3 7-day hold on linux-*-headers. When the headers won the race, the next DKMS rebuild emitted:
ERROR: Missing 6.18.29-1-lts kernel modules tree for module nvidia/595.71.05.
After reboot the running kernel was the old held one, nvidia.ko wasn't built for any kernel on disk, and the GPU dropped to simpledrm. This release closes that race.
What's new
- Auto-coupling.
<X>-headersnow inherits Tier 1 whenever<X>is Tier 1. Hardcoded, always on. Same PKGBUILD → same build date → same hold expiry, so kernel and headers always bucket together. [groups]table (optional) intier-pins.toml— escape hatch for non-standard kernel names (linux-cachyos-cacule-headers) or for bundling extras likenvidia-utilsinto a kernel's tier.- Plan-time desync detector — every
nog updatechecks installed kernel vs. installed headers versions for each Tier 1 kernel. Mismatches print a red ⚠ warning block with both versions named. nog update --realign— forward-path recovery. Pulls held kernels into Ready when their pending upgrade matches the installed headers version, so the next transaction realigns kernel ↔ headers in a single coherent step.
Migration notes
After upgrading, the first nog update will show linux-headers, linux-zen-headers, linux-lts-headers, and linux-hardened-headers under Held with 30-day windows where v1.0.2 showed them as Ready with 7-day windows. This is the protection working — those headers should never have been able to flow ahead of their kernel.
Existing tier-pins.toml files without a [groups] section keep working unchanged.
Verify the fix is active
nog search linux-zen-headers
# expect: red [Tier 1 — 30d hold] annotationA green Tier 3 annotation means the upgrade didn't apply.
Recovery from a system already in the desynced state
nog update --realign
...or the documented manual path if --realign doesn't apply (headers are ahead of any pending kernel upgrade). Full recovery recipes are in README.md → Troubleshooting and man nog.
Under the hood
- Tests: 6 → 14 (8 new in
tiers::testscovering the coupling matrix) - TEST-MATRIX section 16: 16 new regression-guard checks
- New
testing/folder layout matching the KognogOS convention (date-prefixed Test Matrix + Test Results + project release checklist) - No new dependencies; same dynamic-libzstd linking contract as v1.0.1 / v1.0.2
- DKMS modules themselves are not coupled — they succeed automatically once kernel ↔ headers are coherent
Full changelog with the failure narrative: README → v1.0.3.
🤖 Generated with Claude Code
Co-developed by jetomev (idea, vision, direction, testing) and Claude (architecture, implementation).
Assets 2
v1.0.2 — dogfood-surfaced polish batch
v1.0.2 — five fixes and two matrix refinements surfaced by the v1.0 dogfood
The end-to-end dogfood of the AUR-installed v1.0.1 binary surfaced a handful of small rough edges — misleading labels, a Rust-native panic in a reachable error path, embedded build paths leaking into release binaries, and a duplicated phrase in error messages. All fixed here. See TEST-REPORT-v1.0.md for the full matrix audit that caught every item.
Fixes
- 🛑 F5 —
load_tiers()no longer panics. Missing or unreadable `tier-pins.toml` now produces a clean `eprintln!` + `exit(1)`, with the attempted path shown so the user can diagnose without having to re-run with `RUST_BACKTRACE`. - 🗂 F4 — Single-warning config load. `NogConfig::load_default()` is now cached via `OnceLock`. Duplicate "no nog.conf found" warnings on misconfigured systems are gone, and repeat callers read from the cache instead of re-hitting the filesystem.
- 🔒 F2 — Release binaries no longer embed the maintainer's build path. The `CARGO_MANIFEST_DIR` dev-fallback branch is gated behind `#[cfg(debug_assertions)]`. `strings` checks on the release binary come up clean; dev clones still work as before via `cargo run`. Also resolves the `makepkg $srcdir` warning.
- 🎨 F1 — `nog search` tier annotations are now config-aware and consistent. Tier 1 defaults to `[Tier 1 — 30d hold]` (was the stale `manual sign-off` label from v0.6.0). Flips to `[Tier 1 — manual sign-off]` only when `manual_signoff = true`. Tier 3 shows `[Tier 3 — 7d hold]` for day-count consistency (was `fast-track`). All day counts read from `nog.conf`'s `[holds]` section.
- 📝 F3 — No more duplicated "exit status" phrase. Every `eprintln!("... exited with status {}", status)` now passes `status.code().unwrap_or(-1)` so output reads `exited with status 1` instead of `exited with status exit status: 1`.
Matrix refinements
- 📋 M1 — `TEST-MATRIX.md` check 15.3 relaxed to allow `.pacsave`/`.pacnew` siblings in `/etc/nog/`. They're expected after any uninstall/reinstall cycle on a package with a `backup=` directive (which nog intentionally has, to preserve user tier customizations across upgrades).
- 📋 M2 — `TEST-MATRIX.md` check 3.5 relaxed to drop the strict "nog exits non-zero" criterion for nonexistent packages. Helpers have inconsistent behavior here (yay returns 0 with "nothing to do"; paru may return non-zero).
No behavior changes
- 6/6 hold unit tests still green
- Same `libzstd` via pkg-config dynamic-linking contract as v1.0.1
- No changes to the tier-system contract, AUR integration, privilege model, or any documented command behavior — only error-path polish and corrected user-visible text
What you need to do
`yay -Syy && yay -S nog` once the AUR PKGBUILD is updated to v1.0.2 (coming right after this release).
Assets 2
v1.0.1 — hotfix: AUR build failure on fresh environments
Hotfix — AUR build on clean environments
The v1.0.0 dogfood caught a real regression: yay -S nog failed with linker errors (undefined `ZSTD_*` symbols) because the `zstd-sys` crate's bundled static build didn't emit the right link directives under Arch's makepkg environment (LLD + `-Wl,--as-needed` + `-nodefaultlibs`). Local dev builds (GNU ld default) happened to work; fresh builds under makepkg did not. v1.0.0 was never actually installable on a clean system.
Fix
Switch `zstd` to its `pkg-config` feature in `Cargo.toml`:
```toml
zstd = { version = "0.13", features = ["pkg-config"] }
```
This forces `zstd-sys` to use the system `libzstd` via dynamic linking instead of its bundled static build. System `libzstd` is always present on Arch (pacman itself depends on it); `pkg-config` ships with `base-devel`. Zero new runtime or build dependencies.
What you need to do
- If you tried to install v1.0.0 from AUR and got the build failure: run `yay -Syy && yay -S nog` once the AUR PKGBUILD is updated to v1.0.1 (coming right after this release).
- If you built from source locally with GNU ld: update your local clone (`git pull`); the new Cargo.toml will use `pkg-config` going forward.
Under the hood
- 6/6 hold tests still green
- Smoke test: `nog update` output renders correctly, AUR build dates still resolve via the helper, zstd sync-DB decompression (for Chaotic-AUR repos) still works — pkg-config dynamic linking is fully functional
- No behavior changes; no API changes
Lesson
The dogfood phase is load-bearing. Running `cargo build --release` in the dev tree was never sufficient — it doesn't exercise the makepkg linker env. Future releases should always pass through a `makepkg -si` test in the `aur-nog/` workspace before the AUR push.
Assets 2
v1.0.0 — nog is done cooking
nog 1.0.0 — initial stable release
After six deliberate phases of development, nog crosses from phased alpha into its first stable release. Every planned capability is shipped; the core contract is now frozen for the v1.x line.
What's in the box
- 🎚 Three-tier classification — every package is Tier 1 (kernel/bootloader/glibc/systemd — 30-day hold), Tier 2 (DE and key apps — 15-day hold), or Tier 3 (everything else — 7-day hold). Assignments live in `/etc/nog/tier-pins.toml`.
- 📊 Status-grouped update plan — `nog update` computes a plan before any transaction runs, grouping pending upgrades into Ready, Held, and Unknown buckets with Catppuccin Mocha tier colors.
- 🧩 AUR helper integration — auto-detects yay or paru (`[aur] helper` in `nog.conf` to override). AUR pending upgrades fold into the same bucketing flow; transactions route through the helper for a single combined `-Syu` covering official + AUR.
- 📅 Real build dates — official packages come from pacman sync DBs (gzip + zstd); AUR packages come from the helper's cached metadata (` -Sai`). AUR packages with resolvable dates bucket as Ready/Held, not always Unknown.
- ❓ Interactive Unknown handling — packages with no resolvable build date (locally built, disabled repo, AUR query failure) trigger a per-package y/N prompt; EOF-safe fallback for piped/non-TTY stdin.
- 🧑 Unified no-sudo rule — run `nog` as your regular user, always. nog escalates exactly twice: `sudo pacman` for transactions, `sudo tee /etc/nog/tier-pins.toml` for the one file it writes.
- 🛡 Pacman-native enforcement — holds use pacman's own `--ignore` mechanism. nog cannot silently bypass signatures, conflict resolution, or any other pacman check.
- 📖 Complete documentation — accurate man page (`man nog`), `--help` text for every subcommand, and a thorough Privilege model section documenting every file nog reads, writes, and never touches.
Three invariants
- Pacman-native — nog is a wrapper, never a replacement. Every install, remove, and upgrade goes through pacman's checks.
- Never-surprise — critical packages are held for community testing before reaching your system. No kernel ever updates without a 30-day buffer.
- No-sudo — nog itself never runs as root. Escalation is visible, narrow, and documented.
Known limitations carried into v1.0
- AUR build-date resolution depends on the helper's metadata cache being fresh. If stale, hold windows evaluate against the cached date. Run `yay -Syy` (or equivalent) to refresh.
- AUR packages without a `Last Modified` field still fall into the Unknown bucket and hit the y/N prompt.
Ecosystem
nog is the native package manager for KognogOS. Companions:
- nogforge — TUI wrapper for nog + AUR helpers + Flatpak/Snap
- grubforge — GRUB bootloader TUI, ships as Tier 2
- alacrittyforge — Alacritty configuration TUI, Tier 2
What's next
- AUR v1.0 submission — PKGBUILD is now in the repo at the root; maintainer pushes to `ssh://aur@aur.archlinux.org/nog.git` after `updpkgsums && makepkg --printsrcinfo > .SRCINFO`
- v1.0 dogfood — clean uninstall, fresh install from AUR, full run of `TEST-MATRIX.md`, asciinema screenshots embedded in README
- Longer-term roadmap — first-run Tier 1 policy wizard, Chaotic-AUR binary package, `nog history`, `nog status`, `nog rollback`, hook support
Credits
Development is a collaboration between jetomev (vision, direction, testing) and Claude (Anthropic) (architecture, implementation). Every phase shipped with a tagged pre-release; the v1.0.0 tag is the moment the release kit begins.
Assets 2
v0.12.0 — Phase 5b (docs): man page + help text accuracy pass
Phase 5b (docs) — accuracy pass
User-facing docs catch up with reality. The man page's stale command and tier descriptions (some still reflecting pre-v0.8 behavior) are rewritten; clap help text gets a top-level summary and per-subcommand descriptions.
Highlights
- 📜 Man page rewrite — DESCRIPTION now mentions AUR helper integration and 30/15/7 day windows; COMMANDS accurately describes every subcommand's real v0.12.0 behavior (no more stale "Tier 1 blocked" on install, accurate three-bucket update flow, new unlock semantics); TIER SYSTEM documents the auto-release default and the `manual_signoff = true` expert mode; FILES adds sync DBs and `/etc/pacman.conf` as read paths and notes `sudo tee` for tier-pin writes
- 💬 Clap help text refresh — top-level `long_about` summarizes the tier system and no-sudo rule; every subcommand has both a short description (for the command list) and a longer description shown in `nog --help`
- 🏷 `man nog` header bumped to v0.12.0
Roadmap housekeeping
Screenshots and the v1.0.0 CHANGELOG consolidation moved from Phase 5b into the v1.0 dogfood + release kit step. They belong at release time, not pre-release — screenshots of the dev build would be stale as soon as v1.0 ships from AUR.
Under the hood
- No behavior changes
- 6/6 hold unit tests still green; warnings unchanged at 7
- PRIVILEGES AND SUDO section from v0.10.0 stays intact
What's next
- AUR v1.0 submission — regenerate PKGBUILD + .SRCINFO pinned to a v1.0.0 tarball, push to the AUR git repo
- v1.0 dogfood + release kit — uninstall, rebuild from fresh PKGBUILD, run `TEST-MATRIX.md` end-to-end, capture asciinema screenshots, write the v1.0.0 CHANGELOG consolidation
Assets 2
v0.11.0 — Phase 5a: AUR build-date resolution
Phase 5a — the last Unknown falls
AUR pending upgrades now get real build dates. Packages that used to always land in the Unknown bucket (and hit the
y/N prompt) now bucket as Ready or Held based on their actual age — the exact same treatment as official repo
packages.
Highlights
- 📅 Real dates for AUR packages —
nog updatenow queries the helper's cached AUR metadata via<helper> -Sai,
parses theLast Modifiedfield per package, and converts to Unix timestamp viadate -d - 🧮 Unified build-date map — sync-DB dates (official repos, Chaotic-AUR binary) and helper-resolved AUR dates flow
through the sameholds::evaluate()function. No special-case code paths. - 🛟 Soft-fail discipline preserved — any lookup failure (helper unreachable, missing
Last Modified, unparseable
date) falls back to the Unknown bucket and the existing y/N prompt. No hard errors.
Before / after
Running nog update with fresh-editor-bin (AUR) pending:
Before (v0.10.0):
Unknown (1):
fresh-editor-bin 0.2.24-1 -> 0.2.25-1 [Tier 3 · no build date in sync DB]
fresh-editor-bin (Tier 3 ...) — update anyway? [y/N]
After (v0.11.0):
Held (1):
fresh-editor-bin 0.2.24-1 -> 0.2.25-1 [Tier 3 · 6 days remaining]
No prompt — the tier system made the decision based on the actual date.
Security posture
Zero new crate dependencies. Zero new network surface from nog itself. nog still spawns subprocesses and never touches
the network directly. The helper owns all AUR network I/O, which matches the threat model documented in v0.10.0's
Privilege model section.
Under the hood
- New
aur::build_dates_for(helper, packages)— one batched-Saicall, robustsplit_once(':')parser tolerating
variable column widths across yay/paru, no regex, no new deps - Unknown-bucket message updated to "no resolvable build date" (more accurate now that lookup has multiple paths)
- 6/6 hold unit tests still green; warnings unchanged at 7
What's next
- Phase 5b — documentation polish: full man page rewrite (the COMMANDS and TIER SYSTEM sections still reflect pre-v0.8
behavior), help-text refresh, terminal screenshots, CHANGELOG finalization - AUR v1.0 submission — regenerate PKGBUILD + .SRCINFO pinned to the v1.0.0 tarball
- v1.0 dogfood — uninstall, rebuild from fresh PKGBUILD, run
TEST-MATRIX.mdend-to-end
Assets 2
v0.10.0 — Phase 4: AUR helper integration + no-sudo privilege model
Phase 4 — nog learns to speak AUR
yay and paru are now auto-detected; AUR pending upgrades fold into the same status-grouped output as official repo
packages, and the transaction hands off to the helper for a single combined -Syu covering both. Along the way, nog
gained a unified no-sudo privilege model documented in full.
Highlights
- 🧩 New
aurmodule — helper detection (yay→paru→none) driven by a new[aur] helper = "auto"section in
nog.conf. Supports"auto","yay","paru","none"; hard-errors if a specific helper is requested but missing - 📦 AUR in the update flow —
nog updatecalls<helper> -Quaalongsidecheckupdatesand merges the results. AUR
packages bucket as Unknown (no sync-DB build date) and flow through the existing y/N prompt - 🔄 Helper-driven handoff — when a helper is configured, transactions route through
<helper> -Syu --ignore=...for a
single combined official+AUR upgrade. The helper runs as your user and sudo-s pacman internally - 📥
nog installhandles AUR-only packages automatically — no pre-check; the helper resolves sync repos first, then
AUR - 🔓
nog unlock --promotealso routes through the helper when configured
The no-sudo rule
- 🧑 Run
nogas your user. Neversudo nog.pacman.rsinvokessudo pacmaninternally;tiers::pin_package
writes/etc/nog/tier-pins.tomlviasudo tee. The sudo prompt appears at the exact moment elevation is needed. - 🛑 Root-guard:
sudo nogwith a helper configured (detected via$SUDO_USER/$SUDO_UID) exits with a clear
message pointing you to drop the sudo. Necessary because yay/paru refuse to run as root. - ✅ Fully backwards-compatible on non-helper paths:
sudo nog <cmd>still works (sudo-as-root passes through
transparently).
Documentation
- 📖 New "Privilege model" section in README — exact
sudoinvocations (sudo pacmanandsudo tee /etc/nog/tier-pins.toml), files read without elevation, the single file nog ever writes, and the comprehensive list of
system files nog never touches (/etc/pacman.conf,/etc/pacman.d/**,/var/lib/pacman/local/**, the keyring,
/etc/sudoers, etc.) - 📜 Man page gains a PRIVILEGES AND SUDO section mirroring the README content; header bumped to 0.10.0; EXAMPLES
dropped theirsudoprefixes - Full man page rewrite (stale command/tier descriptions) deferred to Phase 5
Under the hood
- Fully backwards-compatible on the update flow: no helper configured → pacman handoff unchanged
- 6/6 hold unit tests still green, 7 warnings (unchanged since Phase 3)
checkupdatesis unchanged — still runs as user, still no-Syside effects
What's next
Phase 5 — polish: full man page rewrite, help-text refresh, terminal screenshots, AUR build-date lookup via AUR RPC
(so real hold windows eventually apply to AUR packages instead of bucketing them as Unknown), and CHANGELOG finalization
for v1.0.
Assets 2
v0.9.0 — Phase 3: Hold evaluation wired into nog update
Phase 3 — wired into nog update (the tier system goes live)
The 30 / 15 / 7-day hold windows introduced in v0.7.0 and v0.8.0 are now applied end-to-end during a real system upgrade.
Every pending upgrade is classified, evaluated, and grouped into a labelled bucket before pacman ever runs.
Highlights
- 🔌
checkupdatesintegration —nog updatelists pending upgrades viacheckupdates(pacman-contrib), so planning
has no sync-DB side effects - 📊 Status-grouped output — three labelled buckets:
Ready to install,Held,Unknown. Each row shows package
name, version bump, tier, and either "N days past window", "N days remaining", or "no build date in sync DB" - 🎨 Catppuccin Mocha tier colors — Tier 1 red
#F38BA8, Tier 2 yellow#F9E2AF, Tier 3 green#A6E3A1, muted
subtext#A6ADC8for version/metadata - ❓ Interactive
[y/N]prompt for packages with no sync-DB build date (AUR-only, locally built, disabled repo); EOF
/ non-TTY stdin auto-skips remaining Unknowns with a warning instead of hanging
Policy changes
- 🎚 Tier 1 default flipped to novice-friendly —
manual_signoffnow defaults tofalse, so Tier 1 auto-updates once
the 30-day hold expires. Expert users setmanual_signoff = trueto restore always-held-until-promoted behavior. - 🔓
nog unlock <pkg> --promotekept as the escape hatch in both modes: force-upgrade a held Tier 1 package right
now, bypassing the hold and any sign-off. - 🗑 Tier 1 install block removed —
nog install linux-ltsnow proceeds normally; tier classification is shown as
informational output only. Explicit user commands execute user intent; tier protection lives in the passive update path. - 🧹
nog unlockwithout--promotenow honestly reports it has no session state to toggle, and points the user at
--promotefor the real action.
Example output
nog: checking for pending updates...
Ready to install (2):
libmpc 1.4.0-1 -> 1.4.1-1 [Tier 3 · 24 days past window]
lib32-libngtcp2 1.22.0-1 -> 1.22.1-1 [Tier 3 · 14 days past window]
Held (2):
linux 6.19.10-1 -> 6.19.11-1 [Tier 1 · 22 days remaining]
firefox 138.0-1 -> 138.0.2-1 [Tier 2 · 11 days remaining]
Unknown (1):
my-local-pkg 0.9-1 -> 1.0-1 [Tier 3 · no build date in sync DB]
nog: handing off to pacman...
Under the hood
- Orphaned
tiers::tier1_packages()removed (the oldupdate()was its only consumer) is_manual_signoff()now actually in use — previously-unused method is live- Catppuccin color constants centralized in
commands/mod.rsfor future reuse bynog search config::NogConfig::load_default()fallback defaults aligned with the 30 / 15 / 7 canonical spec- Warnings down to 7 (from 9); 6/6 unit tests still green
What's next
Phase 4 — AUR helper detection (yay / paru) with tier-aware holds on AUR packages.
Assets 2
v0.8.0 — Phase 2: Hold Evaluation Logic
Phase 2 — The date-math engine
This release adds the brain that decides whether a package update should actually land. It's the logic layer: given a package, its tier, its build date, and the configured hold window, return one of three states — Expired, Holding, or Unknown.
Like Phase 1, this is infrastructure. No user-facing commands change. Phase 3 is where this wiring becomes visible to you when you run nog update.
What landed
- 🧮 New
holdsmodule — one pure public function,evaluate(). All inputs explicit (includingnow: SystemTime), no side effects. Callable against thousands of packages without cost. - 📊 Three hold states —
Expired { days_past_window },Holding { days_remaining },Unknown(for packages not in any sync DB). - ✅ 6 unit tests covering all three states, the exact-window boundary, partial-day rounding (ceiling per spec), and future-dated packages.
- 🗓 New hold spec now live in
/etc/nog/nog.conf:- Tier 1 = 30 days (kernel, bootloader, glibc)
- Tier 2 = 15 days (desktop environment, key apps)
- Tier 3 = 7 days (everything else)
Config model cleanup
- 🧹 The obsolete
hold_daysfield is removed fromtier-pins.toml. Hold durations are now owned bynog.conf's[holds]section — one source of truth. - 🗑
TierManager::hold_days()method andTierConfig.hold_daysfield removed. - 🎨
TierDisplayimpl simplified — no more hardcoded day counts in the variant name. - 🪫 One warning squashed —
HoldsConfigfields are now active.
What's the same
Every existing nog command behaves identically to v0.7.0. You won't see any new output or behavior changes from this release. The hold evaluator is idle until Phase 3 wires it into nog update.
Verified live
Running _debug-hold against the real 18,000+ package sync DB produced correct results for all three states:
linux— Tier 1 (30d), built 16d ago → HELD, 14 days remainingfirefox— Tier 2 (15d), built 12d ago → HELD, 3 days remainingpacman— Tier 1 (30d), built 97d ago → READY, 67 days past windowvscodium-bin— AUR package, not in sync DB → UNKNOWN
What's next — Phase 3
Wire the evaluator into nog update. New status-grouped output format (Held packages first, Ready-to-install second), Catppuccin tier colors (Red/Blue/Green), and an interactive qualification flow for Unknown packages.
Full v1.0 roadmap:
- ✅ Phase 1 — sync DB reader
- ✅ Phase 2 — hold evaluation logic
- ⏳ Phase 3 — wire into
nog update - ⏳ Phase 4 — AUR helper detection
- ⏳ Phase 5 — polish
See the README for the full roadmap and changelog.