Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20681cd4f1 |
@@ -0,0 +1,141 @@
|
|||||||
|
# Establish InkUI architecture and Linux delivery options
|
||||||
|
|
||||||
|
Research for [Establish InkUI architecture and Linux delivery options](https://git.bongbetic.com/xavierk/odin/issues/6), part of [Find the way to Odin’s build-ready specification](https://git.bongbetic.com/xavierk/odin/issues/1).
|
||||||
|
|
||||||
|
Access date: **2026-09-25**. This report records evidence and conditional recommendations, not an architecture decision. No dependencies were installed, application code built, or benchmarks run. InkUI is a user requirement throughout.
|
||||||
|
|
||||||
|
## Decision summary
|
||||||
|
|
||||||
|
The strongest initial candidate is a TypeScript/React terminal application using **copied InkUI components**, a maintained Node runtime, and separately supervised workload processes. Node 24 provides a maintained baseline today. Ink 7.1.1 offers useful mouse-layout and terminal-lifecycle primitives, but moving InkUI beyond its declared Ink 6 range requires a focused compatibility proof. Staying on Ink 6.8.0 avoids that version change while leaving more application work around positioning and terminal ownership.
|
||||||
|
|
||||||
|
Bun is a credible alternative delivery/runtime candidate because it publishes glibc and musl binaries for both requested architectures and supports compiled executables. Its documented Node compatibility differences mean it needs an explicit subprocess, terminal, and asset-loading qualification before adoption. Neither runtime choice makes every benchmark available on every machine. **Capability coverage**, operating-system support, and comparable **performance measurements** need separate contracts.
|
||||||
|
|
||||||
|
## 1. Exact InkUI identity and maturity
|
||||||
|
|
||||||
|
The requested project is **kamlesh723/InkUI**, not the separate `vadimdemedes/ink-ui` library. Its installer is `@inkui-cli/inkui`; npm reports **0.5.0**, published May 4, 2026. GitHub’s latest release is still **v0.4.0**, published April 12. The inspected main commit is `e3110d89b3f0933bcb297a6af33318124c889f36`, also May 4. Pin the actual source commit and installer version rather than treating those release signals as interchangeable. [1][2]
|
||||||
|
|
||||||
|
InkUI copies `.tsx` source and shared theme code into the consuming project. Individual component packages also exist. The source-copy route fits adapting mouse handling, accessible output, and Bongbetic themes, but transfers responsibility for reviewing upstream fixes and maintaining local changes. Its MIT notice must accompany copied/substantial source. Upstream documentation specifies Node ≥20, React `^19.0.0`, and Ink `^6.0.0`; its CI covers Ubuntu with Node 20, not a Linux/libc/terminal matrix. These facts establish an early component project with useful source, not broad deployment certification. [1][3]
|
||||||
|
|
||||||
|
Verified component capabilities:
|
||||||
|
|
||||||
|
- **Themes:** semantic color tokens, dark/light defaults, custom colors, and border styles. A global theme context is application code in the guide, not automatic global behavior.
|
||||||
|
- **Keyboard:** input components use Ink input handlers; hooks provide indexed focus cycling and key bindings. Odin still owns modal focus, consistent shortcuts, and cancellation.
|
||||||
|
- **Graphs:** Sparkline uses Unicode blocks, averages samples when downsampling, and can display latest/min/max values. Its declared `height` parameter is unused in the inspected implementation. Gauge supports bar, ring, and arc forms with thresholds. These are small displays, not a complete plotting/interaction system.
|
||||||
|
- **Fallback:** ASCII borders exist, but graph glyphs remain Unicode. Terminal sizing tracks resize events and defaults to 80×24.
|
||||||
|
- **Mouse/accessibility:** inspection found no terminal mouse implementation or ARIA annotations in InkUI components; mouse references in the repository belong to its website. The README’s accessibility description is not evidence of complete accessible interactions. [4]
|
||||||
|
|
||||||
|
## 2. Runtime choices and support floors
|
||||||
|
|
||||||
|
| Candidate | Evidence and fit | Decision condition |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Node 24 + React 19 + Ink 6.8.0 | Ink 6.8 requires Node ≥20 and React ≥19; it satisfies InkUI’s declared major range. Node 24 remains supported through April 2028. | Prefer if preserving the declared InkUI range matters most and the interaction proof can supply the missing mouse/terminal behavior cleanly. |
|
||||||
|
| Node 24 + React ≥19.2 + Ink 7.1.1 | The released Ink 7.1.1 manifest requires Node ≥22 and React ≥19.2. It adds public element coordinates and terminal controls useful to Odin. | Prefer if copied InkUI components pass adaptation tests; do not force installation past peer constraints and call that compatibility. |
|
||||||
|
| Node 26 | Scheduled Current release today, with LTS due October 28, 2026. Official Linux builds also require `libatomic`, unlike the Node 24 build documentation. | Consider as a forward-compatibility lane or release baseline after qualification; “newest” alone is insufficient. |
|
||||||
|
| Bun 1.4.2 | Latest inspected release; official x64/arm64 glibc/musl artifacts and executable compilation. Node `tty` is documented as implemented, with behavioral differences; `child_process` and `process` remain partially compatible. | Candidate only after the same terminal, process-tree cancellation, signals, and dependency-asset tests as Node. No InkUI-on-Bun certification was established here. |
|
||||||
|
|
||||||
|
Node 20 reached its scheduled EOL on April 30, 2026; Node 22 is maintained until April 2027, while Node 25 is already EOL. React’s current registry version is 19.3.0, but an actual runtime/renderer pair must be pinned together. The released Ink 7.1.1 manifest differs from its evolving main branch, so use release-tag evidence for implementation. [5][6][7]
|
||||||
|
|
||||||
|
**Node 24’s official Linux baseline** is kernel ≥4.18, glibc ≥2.28, and libstdc++ providing `GLIBCXX_3.4.25`, for x64 and arm64 Tier 1 platforms. Older kernels may run but are not the documented official-binary baseline. Upstream also excludes vendor-EOL operating systems. x64 musl appears as Experimental; arm64 musl is absent from that platform table. Unofficial musl builds exist for both architectures but explicitly disclaim rigorous testing and guarantees. [8]
|
||||||
|
|
||||||
|
Void supplies downstream Node builds: its inspected package recipe is Node 24.18.0 with distribution library dependencies and cross-build handling. That is a viable source of a musl runtime, not proof that an arbitrary downloaded Node binary works on musl. Void itself supports glibc and musl variants. The handbook specifically states that proprietary NVIDIA drivers do not support musl; Odin must explain that limitation rather than attempting to hide it with packaging. [9]
|
||||||
|
|
||||||
|
Bun’s current documentation specifies glibc ≥2.17, x64 SSE4.2/Nehalem or newer, official musl alternatives, and both requested architectures. It recommends kernel ≥5.6 while claiming operation down to 3.10 with degraded newer syscalls. Current x64 documentation says one binary selects AVX paths at runtime; old advice about choosing separate baseline/modern builds is stale. The inspected installation page does not establish a precise musl version floor. Certify the chosen release and artifact; do not interpret a runtime boot floor as Odin’s complete feature floor. [7]
|
||||||
|
|
||||||
|
## 3. Mouse, terminal behavior, and accessibility
|
||||||
|
|
||||||
|
**Mouse is the main UI feasibility gate.** Xterm defines reporting modes and SGR mouse encoding; enabling reporting is only the transport. Odin also needs event decoding, click/wheel semantics, clipping, focus transfer, hit testing, and restoration of modes. A small established input adapter is worth assessing before custom parsing, but this investigation does not endorse an unexamined package. InkUI remains the component source. [10]
|
||||||
|
|
||||||
|
Ink 6’s public measurement API returns only dimensions. Ink 7.1.1 returns `x`, `y`, width, and height after layout. Its documentation explicitly warns that these coordinates are relative to the live layout, not the terminal viewport. Static output above the live region, scroll offsets, borders, and resizing must be accounted for before comparing mouse coordinates. Neither inspected Ink API supplies a complete mouse interaction system. The proof should cover clicking a scrolled table row, scrolling inside a panel, overlapping dialogs, resizing, and keyboard parity. [5][11]
|
||||||
|
|
||||||
|
Ink 7.1.1 documents alternate-screen ownership, noninteractive output, render-rate control, terminal suspension, and screen-reader mode. Noninteractive rendering emits only the final non-static frame at unmount, which is not a sufficient progress/reporting policy by itself. Ink’s basic screen-reader mode supports a subset of ARIA and `INK_SCREEN_READER=true`; Odin must add meaningful labels, numeric graph alternatives, state descriptions, and restrained updates. Release-tag documentation says raw-mode setters can throw when unsupported; indexed main-branch documentation described newer behavior. Do not mix these contracts. [11]
|
||||||
|
|
||||||
|
Recommended terminal contract for the subsequent UX decision:
|
||||||
|
|
||||||
|
- Full interactive layout in certified terminals; keyboard access to every action; mouse where reporting is available. Mouse absence should not make a run unusable.
|
||||||
|
- An explicit plain mode for redirected output, unavailable raw input, `TERM=dumb`, and accessibility preferences. Keep readable progress, result summaries, and noninteractive arguments for Bash automation. Bash support means a normal executable and stable exit behavior; orchestration should not depend on users’ shell aliases or startup files.
|
||||||
|
- Independent controls for color, Unicode decoration, animation, and interactive layout. `NO_COLOR` concerns ANSI color and explicitly does not disable bold/underline; it is not an ASCII or screen-reader switch. Graph numbers and health states must remain understandable without color. [12]
|
||||||
|
- No unsupported claim that `$TERM` alone proves capability. Qualify an xterm-compatible/VTE terminal, a modern enhanced-protocol terminal, SSH with a PTY, tmux with mouse on/off, Linux console, and pipes. tmux mediates events and terminal features; its configuration and remote terminfo are part of the compatibility environment. [13]
|
||||||
|
- On normal exit, cancellation, exceptions, SIGTERM, and terminal handoff: restore raw mode, mouse reporting, cursor, and screen state. SIGKILL cannot execute application cleanup; qualify recovery behavior and a readable rerun, without promising impossible restoration guarantees.
|
||||||
|
|
||||||
|
## 4. Distribution and offline execution
|
||||||
|
|
||||||
|
Treat **xbps, deb, and rpm as delivery formats**, not interchangeable dependency namespaces or compatibility guarantees. A native payload still carries architecture, libc, shared-library, and CPU constraints. Debian’s policies distinguish absolute dependencies from recommendations and require generated shared-library dependencies; RPM records requirements and package signatures; Void separates architecture/libc repositories and requires signed remote repositories. [14]
|
||||||
|
|
||||||
|
Three delivery options merit a final choice:
|
||||||
|
|
||||||
|
| Delivery | Advantage | Ownership cost / qualification |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Native packages using a maintained distro Node | Distro security updates, conventional dependency ownership, natural Void musl integration. | Supported distro releases must provide the selected runtime range; package names and versions vary. JS-only files can be architecture-independent, but included runtime/helper binaries cannot. |
|
||||||
|
| Portable archive containing pinned Node plus built JS/assets | Predictable runtime without npm on the target; simple inspection and Bash launcher. | Separate x64/arm64 and glibc/musl artifacts; Bongbetic owns runtime security updates, signatures, licenses, and musl build provenance. A bundled runtime still has system-library requirements. |
|
||||||
|
| Bun compiled executable | Documented targets cover the four architecture/libc combinations and can embed assets. | A separate binary per target still needs qualification. Current docs enable `.env`/`bunfig.toml` autoloading by default; deterministic execution should disable or explicitly control that behavior. Subprocess compatibility remains a gate. |
|
||||||
|
|
||||||
|
Node 24’s single-executable feature is in active development and embeds a CommonJS script; ESM dependencies, bundled assets, and cross-platform code-cache restrictions add work. It should not be the default merely to produce one file. A portable directory can be a complete product. [15]
|
||||||
|
|
||||||
|
Recommend separating acquisition from a **benchmark run**. Core UI, manifests, fixtures, and chosen baseline workloads should run offline once prepared. Optional tools, browser engines, language toolchains, and large datasets need declared versions, origins, digests, licenses, sizes, and cache locations. Distribution packages or a verified offline bundle can supply them. Installation should be an explicit preparation action; a timed measurement must not fetch “latest,” upgrade drivers, or change kernel settings.
|
||||||
|
|
||||||
|
When a dependency is unavailable, record a precise capability-coverage reason. Do not replace a workload silently and reuse its score identity. Decide later whether the default installer acquires the full standard run profile or a smaller core with optional packs. Keep package-manager scripts and network access out of privileged measurement operations.
|
||||||
|
|
||||||
|
## 5. Measurement and privilege boundaries
|
||||||
|
|
||||||
|
A UI runtime does not need to be the workload implementation language. Node’s asynchronous child-process API can orchestrate existing executables without a shell, so the evidence does not require a second application language now. A native helper becomes justified if a selected workload needs precise memory access, direct kernel APIs, or a small enforceable watchdog/privilege boundary that existing tools do not provide. That choice belongs after workload requirements are known. [16]
|
||||||
|
|
||||||
|
Proposed ownership boundaries:
|
||||||
|
|
||||||
|
1. An unprivileged InkUI process owns navigation, branding, readable progress, and reports.
|
||||||
|
2. A runner owns the run manifest, executable identity, timing, output limits, process lifecycle, and persisted measurements. Use explicit arguments and controlled environment variables, not shell command construction.
|
||||||
|
3. Privileged operations, when required, receive narrowly validated operation/target requests. Do not elevate the complete React/Bun/Node application or expose a generic root command executor. Validate device identity, paths, ownership, and temporary-file boundaries; retain original-user ownership of local results. Read-only diagnostics and storage writes require distinct authorization/safety rules.
|
||||||
|
|
||||||
|
UI graphs, animation timers, garbage collection, logging, and synchronous parsing can perturb CPU, memory, and I/O measurements. Separate processes prevent event-loop coupling but still share hardware. Recommend pausing decorative updates during timed windows, buffering bounded observations, and reporting afterward. If live charts remain necessary, cap their sampling/render rate and quantify UI-on versus quiet-mode overhead on low-end hardware. Do not silently reserve a core or change affinity/governors: these alter the benchmark’s execution conditions. Record any chosen isolation policy in the run manifest.
|
||||||
|
|
||||||
|
Cancellation is more than calling `child.kill()`: Node documents that killing a parent does not kill Linux descendants. A runner needs process-group ownership, staged termination, exit collection, and orphan handling after UI failure. cgroup v2 can provide stronger group limits and termination, but controller availability and delegation permissions must be probed. Kernel documentation states that controller exposure depends on configuration and hierarchy ownership; `cgroup.kill` and memory limits cannot be presumed available on every system. No systemd dependency is necessary for the core model. [16][17]
|
||||||
|
|
||||||
|
For dangerous pressure profiles, refuse execution when required containment or the independent watchdog cannot be established; explain the unavailable capability. A plain performance run can use a simpler supervision path if its workload contract allows it. Discover actual kernel interfaces such as PSI files rather than assuming them from version numbers; record missing features without inventing zero pressure. [17][18]
|
||||||
|
|
||||||
|
## 6. Proposed certification matrix
|
||||||
|
|
||||||
|
These are future release gates, not completed tests. Use exact image/artifact digests and record kernel, architecture, libc, runtime, terminal, and relevant permissions.
|
||||||
|
|
||||||
|
| Lane | Suggested coverage | What it establishes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Native packages | Void glibc + musl; maintained Debian/Ubuntu; maintained Fedora and enterprise RPM family. | Install, upgrade/remove, dependency declarations, offline start, paths/ownership, normal-user behavior. |
|
||||||
|
| Architecture/libc | x86_64/glibc, x86_64/musl, aarch64/glibc, aarch64/musl. At least Void and Alpine as distinct musl environments if both are claimed. | Loader/runtime and transitive-asset compatibility. Native ARM hardware is required before treating emulation success as ARM performance evidence. |
|
||||||
|
| Kernel/permissions | Oldest promised supported ABI; supported LTS and current distro kernels; runit and systemd; cgroup v2 delegated/denied/absent; restricted proc/sys access. | Capability probing, fallback, supervision, explicit refusal where safe containment is unavailable. |
|
||||||
|
| Terminal/input | Local VTE/xterm-compatible terminal, a modern terminal, SSH PTY, tmux, Linux console, 80×24 and narrow resize, Unicode/ASCII, no color, screen reader, piped output. | Input, readable numeric alternatives, output contract, cleanup, no raw-mode crash. |
|
||||||
|
| Failures | Cancel each workload phase, terminate UI/runner, missing tool, permission denial, low disk space, invalid persisted result. | Process/resource cleanup, bounded logs, durable result state, useful failure explanations. |
|
||||||
|
| Physical measurement | Intel/AMD x86_64 and ARM; AMD/Intel/NVIDIA graphics where supported; NVMe/SATA/HDD; laptops with thermal/power transitions. | Device visibility, real drivers, SMART interpretation paths, thermal effects, representative performance and UI-overhead measurement. |
|
||||||
|
|
||||||
|
VMs are suitable for package/ABI/terminal/failure-path qualification and measuring the VM itself. Virtual storage, virtual GPUs, host scheduling, and hidden hardware telemetry cannot certify physical drive replacement advice, native GPU performance, or host memory health. Passthrough creates a separate recorded environment, not an exemption from those distinctions. Real faults should be covered with parser fixtures and controlled validation; do not deliberately damage hardware to prove a health rule.
|
||||||
|
|
||||||
|
## 7. Decisions still required
|
||||||
|
|
||||||
|
1. Node 24 versus another maintained runtime; Ink 6 compatibility versus adapting copied components to Ink 7; exact version pin and upgrade policy.
|
||||||
|
2. Native-package dependencies, portable runtime archives, or both; who maintains and certifies musl builds; minimum OS/kernel/libc/CPU contract.
|
||||||
|
3. A mouse/focus/terminal-lifecycle prototype retaining InkUI, plus the accessible/plain output acceptance criteria.
|
||||||
|
4. Core versus optional offline workload packs, licensing and size limits, and dependency acquisition policy.
|
||||||
|
5. Per-workload privilege/containment requirements, behavior after UI death, and the quantitative UI-overhead acceptance threshold.
|
||||||
|
6. Exact release certification matrix and which capabilities can be certified only on physical hardware.
|
||||||
|
|
||||||
|
Evidence limits: no compatibility or performance claim was established by execution; no universal Node/Bun/InkUI bundle was produced; installed Void package availability on every target was not checked; Bun’s precise musl floor and InkUI-on-Ink-7/Bun behavior remain unverified. Browser/driver/workload selection and scoring are separate investigations.
|
||||||
|
|
||||||
|
## Sources and method
|
||||||
|
|
||||||
|
All sources below were inspected on **2026-09-25**. Context7 library resolution preceded documentation queries for Node, Ink, Bun, XBPS/Void, Debian Policy, RPM, and tmux. Two earlier exact-InkUI searches returned unrelated libraries and were rejected; the requested repository was inspected directly. Context7 results tracking `master` were checked against released source where version behavior mattered. No quota error occurred.
|
||||||
|
|
||||||
|
1. [InkUI README at inspected commit](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/README.md), [installer manifest](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/apps/cli/package.json), [npm registry](https://registry.npmjs.org/@inkui-cli%2Finkui).
|
||||||
|
2. [InkUI v0.4.0 release](https://github.com/kamlesh723/InkUI/releases/tag/v0.4.0), [inspected commit](https://github.com/kamlesh723/InkUI/commit/e3110d89b3f0933bcb297a6af33318124c889f36).
|
||||||
|
3. [InkUI MIT license](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/LICENSE), [installation guide](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/apps/docs/content/getting-started/installation.mdx), [CI](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/.github/workflows/ci.yml).
|
||||||
|
4. InkUI inspected source: [themes](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/packages/core/src/theme.ts), [hooks](https://github.com/kamlesh723/InkUI/tree/e3110d89b3f0933bcb297a6af33318124c889f36/packages/hooks/src), [Sparkline](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/packages/sparkline/src/Sparkline.tsx), [Gauge](https://github.com/kamlesh723/InkUI/blob/e3110d89b3f0933bcb297a6af33318124c889f36/packages/gauge/src/Gauge.tsx).
|
||||||
|
5. [Ink 6.8.0 README](https://github.com/vadimdemedes/ink/blob/v6.8.0/readme.md), [Ink 7.1.1 manifest](https://github.com/vadimdemedes/ink/blob/v7.1.1/package.json), [Ink npm metadata](https://registry.npmjs.org/ink), [React registry](https://registry.npmjs.org/react/latest).
|
||||||
|
6. [Node official release schedule](https://github.com/nodejs/Release/blob/main/schedule.json), [Node 26 platform/build document](https://github.com/nodejs/node/blob/v26.x/BUILDING.md).
|
||||||
|
7. [Bun 1.4.2 release](https://github.com/oven-sh/bun/releases/tag/bun-v1.4.2), [installation/platform requirements](https://bun.com/docs/installation), [Node API compatibility](https://bun.com/docs/runtime/nodejs-compat).
|
||||||
|
8. [Node 24 supported platforms and official binary requirements](https://github.com/nodejs/node/blob/v24.x/BUILDING.md), [unofficial-builds limitations and targets](https://github.com/nodejs/unofficial-builds/blob/main/README.md).
|
||||||
|
9. [Void Node package recipe](https://github.com/void-linux/void-packages/blob/master/srcpkgs/nodejs/template), [Void musl support and incompatible software](https://docs.voidlinux.org/installation/musl.html).
|
||||||
|
10. [Xterm control sequences: mouse tracking and SGR encoding](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking).
|
||||||
|
11. [Ink 7.1.1 released README](https://github.com/vadimdemedes/ink/blob/v7.1.1/readme.md), [released measurement implementation](https://github.com/vadimdemedes/ink/blob/v7.1.1/src/measure-element.ts).
|
||||||
|
12. [NO_COLOR informal standard and FAQ](https://no-color.org/).
|
||||||
|
13. [tmux getting started](https://github.com/tmux/tmux/wiki/Getting-Started), [modifier keys and terminfo](https://github.com/tmux/tmux/wiki/Modifier-Keys), [tmux manual source](https://github.com/tmux/tmux/blob/master/tmux.1).
|
||||||
|
14. [Void repositories](https://docs.voidlinux.org/xbps/repositories/index.html), [Void signing](https://docs.voidlinux.org/xbps/repositories/signing.html), [Debian package relationships](https://www.debian.org/doc/debian-policy/ch-relationships.html), [Debian shared-library dependencies](https://www.debian.org/doc/debian-policy/ch-sharedlibs.html), [RPM dependency tags](https://github.com/rpm-software-management/rpm/blob/master/docs/manual/tags.md), [RPM package signatures](https://github.com/rpm-software-management/rpm/blob/master/docs/manual/format_v4.md).
|
||||||
|
15. [Bun executable targets, embedding, and autoload controls](https://bun.com/docs/bundler/executables), [Node 24 single-executable applications](https://github.com/nodejs/node/blob/v24.x/doc/api/single-executable-applications.md).
|
||||||
|
16. [Node child-process API: spawn, detached processes, signals, and descendant caveat](https://nodejs.org/docs/latest-v24.x/api/child_process.html).
|
||||||
|
17. [Linux cgroup v2: delegation, controllers, memory limits, and cgroup.kill](https://docs.kernel.org/admin-guide/cgroup-v2.html).
|
||||||
|
18. [Linux pressure stall information](https://docs.kernel.org/accounting/psi.html).
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
# Storage measurements and trustworthy health advice
|
|
||||||
|
|
||||||
Research for [Establish storage measurements and trustworthy health advice](https://git.bongbetic.com/xavierk/odin/issues/4), part of Odin's Wayfinder map. Access date for every source: **2026-09-25**.
|
|
||||||
|
|
||||||
This report establishes evidence and candidate policies. It does not select Odin's final workloads, thresholds, privileged execution design, or score. No benchmark, device query, self-test, installation, or hardware change was performed during this investigation.
|
|
||||||
|
|
||||||
## Findings that shape the decision
|
|
||||||
|
|
||||||
The strongest candidate is **fio for file-based performance measurements, smartmontools for cross-protocol health findings, and an optional nvme-cli adapter for additional NVMe evidence**. These tools cover different responsibilities. A fast benchmark cannot establish drive health; a passing SMART status cannot establish future reliability. Health findings should therefore remain visible independently of the performance score and capability coverage.
|
|
||||||
|
|
||||||
There is a material compatibility change already: nvme-cli **v3.1**, released September 18, 2026, documents `nvme log smart`; `nvme smart-log` is a deprecated compatibility alias. Its default output format version is now 2, with version 1 available. fio **3.43** was released September 23. A bleeding-edge development environment is compatible with reproducible measurements only if Odin records tool versions and keeps workload and parser versions explicit. Package-manager availability alone does not establish supported commands or JSON schemas. [S1][S3]
|
|
||||||
|
|
||||||
## Candidate tools and measurement scope
|
|
||||||
|
|
||||||
| Candidate | Useful responsibility | Limits and recommendation to consider |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| fio | Sequential/random reads and writes, block sizes, queue depths, latency distributions, bounded I/O, optional verification | Best primary workload candidate. Select a small fixed workload vocabulary; do not accept arbitrary user-supplied job files into privileged execution. |
|
|
||||||
| smartctl | ATA, SCSI and NVMe identity, health, existing error/self-test logs; JSON; many bridge/controller adapters | Best baseline health reader. Decode protocol-specific semantics and command status separately. Some transports are unsafe for automatic probing. |
|
|
||||||
| nvme-cli | NVMe-specific identity, SMART and detailed logs | Useful optional supplement. Version 2/3 command and JSON differences need explicit compatibility handling. Avoid duplicating the same controller's health as several independent findings. |
|
|
||||||
| Native `/proc` and `/sys` | I/O pressure, completed I/O, queue activity and available sensors | Low-dependency contextual evidence, not a workload or a substitute for SMART. |
|
|
||||||
| GNU `dd` | Bounded sequential copying, optionally direct I/O and final synchronization | Possible explicitly labelled basic fallback. Its copy-oriented output does not supply fio's workload control or latency distributions; its result must not silently substitute into the same scored workload. |
|
|
||||||
|
|
||||||
Sources: fio HOWTO, smartctl manual, nvme-cli released documentation, kernel PSI/I/O documentation and GNU manual. [S1–S4][S8][S9][S14]
|
|
||||||
|
|
||||||
A compact candidate performance set is:
|
|
||||||
|
|
||||||
| Measurement | Candidate workload, still to be selected | What its result means |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Sequential read/write | Large blocks, for example 1 MiB, one job, depth 1 | Large-file throughput through the selected filesystem and storage path |
|
|
||||||
| Random read/write | 4 KiB, one job, depth 1 | Small-request responsiveness; report latency and IOPS |
|
|
||||||
| Queued random read | Same block size at a documented higher depth, such as 16 or 32 | Concurrency capability; a different workload from depth 1 |
|
|
||||||
| Durable small writes | A separate small, bounded workload with defined sync frequency | Application-visible cost of requesting persistence |
|
|
||||||
| Optional integrity check | Write and verify Odin-owned file blocks with fio checksums | Whether the tested data path returned those bytes correctly; not a full-surface drive or whole-RAM certification |
|
|
||||||
|
|
||||||
Record read and write throughput in explicit units, IOPS, completed bytes, operation count, errors, elapsed time, and p50/p95/p99 latency where sample counts support them. Distinguish fio completion latency from total latency: total includes submission latency. Record achieved queue-depth distribution; requesting depth greater than one does not make a synchronous engine asynchronous. fio `psync` is a useful depth-1 compatibility candidate; `io_uring` and `libaio` are queued-engine candidates where supported. Engine changes must be visible in results and comparability rules. [S1]
|
|
||||||
|
|
||||||
Measure one storage workload at a time during reference runs. Concurrent CPU or memory stress can instead be an explicitly identified contention experiment. Record filesystem, mount options, device topology, encryption/RAID/virtualization, kernel, selected engine, power/thermal state, background I/O, and pre/post free space. The measurement describes this path under these conditions, not the NVMe/HDD in isolation.
|
|
||||||
|
|
||||||
## Safe operation and comparability constraints
|
|
||||||
|
|
||||||
The following are proposed invariants, rather than finalized profile numbers:
|
|
||||||
|
|
||||||
1. **Own every writable byte.** Create a private run directory on a deliberately selected filesystem and exclusively create its regular files. Validate ownership, type and target identity; reject symlink redirection and raw block/character devices. `O_CREAT|O_EXCL` supplies exclusive creation semantics. Do not use arbitrary existing user files as write targets. Avoid selecting `/tmp` automatically: tmpfs stores files in virtual memory and may use swap. [S7][S11]
|
|
||||||
2. **Budget storage space and cumulative writes separately.** fio `size` defines the working region, while `io_size` can independently bound I/O. `runtime` stops at the earlier of completion or time limit; `time_based` loops the workload. Thus a small file plus a timed loop can write many times its size. Prefer explicit byte and time bounds without `time_based` for ordinary write profiles. Count fixture preparation, repetitions and verification-related writes in a per-run host-write budget. Reserve free space, account for quotas and metadata, recheck during execution, and stop on ENOSPC or I/O errors. Space and byte thresholds remain product decisions. [S1]
|
|
||||||
3. **Do not promise a physical NAND-write limit.** A workload's host bytes are measurable; filesystem/controller write amplification and unrelated host activity are additional. NVMe Data Units Written measures host data in units of 1,000 × 512 bytes, rounded up, excluding metadata; it is not a universal NAND-wear counter. Background activity also prevents attributing its entire delta to Odin. [S5]
|
|
||||||
4. **Make cache and durability modes explicit.** fio `direct=1` normally requests `O_DIRECT`; support and alignment vary by filesystem and kernel, and misaligned requests can fail or fall back to buffered I/O. Direct I/O does not by itself provide `O_SYNC` persistence guarantees, bypass every device cache, or prove sustained media speed. `invalidate` is conditional on platform/file support. Avoid global `drop_caches`: kernel documentation warns of additional I/O and CPU costs. A buffered fallback must be labelled and excluded from direct-I/O comparisons. [S1][S7][S12]
|
|
||||||
5. **Include preparation and flush costs honestly.** Read tests over newly created fixtures still require writes. A user choosing no writes can reuse an identified valid fixture or skip that workload; Odin should not create one silently. Do not measure unwritten sparse-file holes as disk reads. For writes, document `end_fsync` or other synchronization and report end-to-end time including the final flush separately from unsynchronized throughput. Control data compressibility/deduplication using a declared fio buffer policy; generating fresh data adds CPU cost. Preserve normal filesystem settings rather than silently disabling compression or copy-on-write. [S1][S7]
|
|
||||||
6. **Treat cancellation and cleanup as part of the run.** Bound the entire job group; stop launching work on cancellation, retain partial status, reap workers, and remove only proven Odin-owned artifacts. A worker stuck in kernel I/O may not stop immediately. Crash recovery needs a manifest and ownership checks before deletion. Cleanup failure is a reported outcome, never a reason to recursively delete a user-selected directory.
|
|
||||||
7. **Collect health before load and reduce work when evidence is serious.** A candidate policy is to skip storage stress when critical media/reliability findings or current unreadable data are already present. Pause on documented thermal alarms or loss of safety headroom. Display estimated host writes before a write run. Avoid automatic discard/TRIM, formatting, SMART feature changes, firmware updates, cache-policy changes or repair operations as benchmark preparation.
|
|
||||||
|
|
||||||
Short bounded tests cannot establish steady-state SSD performance after exhaustion of a large write cache, or scan every HDD sector. Making test data larger than all caches can conflict with a quick run and a conservative write budget. Report the actual duration and working set; do not extrapolate a short burst into an endurance or sustained-performance guarantee. The tradeoff between low impact and sustained measurements needs an explicit run-profile decision.
|
|
||||||
|
|
||||||
## Health evidence and field interpretation
|
|
||||||
|
|
||||||
Prefer structured output with the original tool version, schema identifier, command outcome, timestamp, device identity and transport. A missing field is unknown, not zero. Preserve large counters losslessly: smartctl JSON can emit string/byte-array companions for integers exceeding JavaScript's safe integer range; `--json=v` requests them consistently. This matters for an Ink/JavaScript consumer. [S2]
|
|
||||||
|
|
||||||
For smartctl NVMe output, the primary object is `nvme_smart_health_information_log`. The inspected source confirms the following keys and conversions. Raw NVMe temperature is Kelvin; smartctl's `temperature` here is already Celsius. Do not convert it twice. [S6]
|
|
||||||
|
|
||||||
| Evidence | Meaning | Candidate interpretation |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `critical_warning` bit 0; `available_spare` vs `available_spare_threshold` | Spare capacity below the controller's threshold | Urgent preservation/service finding; display the device-provided threshold |
|
|
||||||
| Bit 1; `temperature`, warning/critical temperature time | Above an over-temperature or below an under-temperature threshold | Stop heat-producing tests; investigate cooling/environment. This alone is not proof that replacement is needed |
|
|
||||||
| Bit 2 | NVM subsystem reliability degraded | Urgent backup and replacement/service assessment |
|
|
||||||
| Bit 3 | Media placed read-only for a device reliability condition | Urgent preservation and replacement/service assessment; distinct from user namespace write protection |
|
|
||||||
| Bits 4/5 | Volatile-memory backup failure; persistent-memory region read-only/unreliable | Urgent loss-of-protection/service finding when applicable; explain the specific subsystem |
|
|
||||||
| `percentage_used` | Vendor estimate of endurance consumed | 100 means estimated endurance consumed, **not guaranteed failure**; values may exceed 100. Plan replacement according to manufacturer guidance and workload, without inventing days remaining |
|
|
||||||
| `media_errors` | Unrecovered data-integrity errors, including ECC/CRC/tag errors | Investigate any nonzero history; escalating recent deltas plus failed I/O are much stronger urgent evidence than an isolated old count |
|
|
||||||
| `num_err_log_entries` | Lifetime number of error-information entries | Inspect status/cause and recency. It is not interchangeable with media errors |
|
|
||||||
| `unsafe_shutdowns` | Loss of power without shutdown notification | Investigate shutdown/power history and correlate with errors; not proof of failed media |
|
|
||||||
| `data_units_written`, power-on hours, thermal counters | Usage/history with specified units and reporting limits | Useful trends and context; no universal lifespan formula |
|
|
||||||
|
|
||||||
NVMe warning bits are current state, not persistent event history; zero today does not erase yesterday's finding. Some temperature fields are optional, and zero can mean unsupported. Per-namespace SMART is optional; the global namespace identifier can describe a controller's aggregate. Preserve scope rather than assigning identical controller totals to every namespace. [S3][S5][S6]
|
|
||||||
|
|
||||||
**ATA needs a separate mapping.** Keep attribute ID, raw representation, normalized current/worst value, threshold, type and failure state. smartctl states that these meanings are vendor-specific; SSD meanings can differ and displayed names can be wrong for models absent from its drive database. The label `Pre-fail` by itself does not mean a drive is failing: the current normalized value must cross its threshold. [S2]
|
|
||||||
|
|
||||||
Common drive-database candidates include reallocated sectors (5), pending sectors (197), offline uncorrectable sectors (198), and interface CRC errors (199). Interpret them only with a matching model/firmware/database rule; do not apply a universal raw-count threshold or turn interface errors directly into a disk-replacement recommendation. Preserve lifetime history and recent deltas separately. SMART RETURN STATUS, failed applicable thresholds, existing self-test failures, and observed host I/O errors are stronger when they agree. SCSI health uses its own exception/sense reporting rather than ATA attribute assumptions. [S2][S15]
|
|
||||||
|
|
||||||
smartctl exit status is a bitmask. Bits 0–2 can describe invocation/access/command problems; bits 3–7 describe failing status, thresholds and historical error/self-test evidence. A nonzero exit must not discard usable JSON, and access failure must not become “bad drive.” Reading an existing self-test log is different from starting a test. The manual notes that running self-tests can degrade performance and normal I/O can extend their duration; any future self-test workflow needs a separate user decision and scheduling. [S2]
|
|
||||||
|
|
||||||
## Candidate advice rubric
|
|
||||||
|
|
||||||
This rubric is a proposed interpretation layer over the documented evidence, not a manufacturer's warranty or an adopted Odin policy.
|
|
||||||
|
|
||||||
| Finding class | Evidence sufficient to consider it | Appropriate wording/action |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| **Replace/service now** | Credible ATA failing status/current applicable prefailure threshold; NVMe degraded reliability/read-only media; serious repeated data-integrity failures attributable to the device | “Preserve accessible data now; avoid further stress; arrange replacement or service.” Cite exact flags, device scope and timestamps. Hardware attribution may still need confirmation |
|
|
||||||
| **Investigate urgently** | New media errors, pending/uncorrectable sectors, recent failed self-tests, resets/timeouts, thermal alarms, loss of power-loss protection | Identify the failing path; correlate controller, connection, power and filesystem evidence. Do not automatically blame the medium |
|
|
||||||
| **Monitor / plan replacement** | Stable historical findings or vendor-estimated endurance consumed without current failure evidence | Retain trends, explain wear status and manufacturer limits, and plan according to importance/workload. No invented remaining-life percentage |
|
|
||||||
| **No concerning evidence observed** | Successful supported collection with no relevant current finding | State what was checked and when; keep normal backup advice independent of a performance score |
|
|
||||||
| **Unknown / limited coverage** | Missing permission/tool/field, sleeping drive, unsupported bridge/controller, virtual device, ambiguous identity | Explain the missing capability and a bounded next step. Never convert unavailable evidence into a healthy badge |
|
|
||||||
|
|
||||||
The smartctl manual recommends preserving data promptly when the drive reports failing health. Conversely, Google's primary HDD population study found that SMART-only models were unlikely to predict individual failures reliably. That older HDD result is not a calibrated modern-SSD failure model, but it reinforces the distinction between a useful warning and a guarantee of future health. NVMe's own endurance-field semantics explicitly reject equating 100% usage with failure. [S2][S5][S16]
|
|
||||||
|
|
||||||
## Compatibility, privilege and general health
|
|
||||||
|
|
||||||
USB, SAT and RAID support must follow known transport rules. The smartctl manual documents bridge-specific NVMe adapters and per-physical-disk MegaRAID addressing; a RAID logical volume is not automatically one physical drive. Particularly important: its **JMB39x/JMS56x transport uses READ/WRITE commands to a RAID-volume sector**. It warns that the wrong device can be overwritten and interruption can prevent restoration. Exclude these from routine automated probing; “try every device type” is not a safe compatibility strategy. Even standby-aware queries may wake a disk during autodetection, so record unsupported power-state handling. [S2]
|
|
||||||
|
|
||||||
VMs need an explicit virtual-device classification. QEMU's NVMe implementation constructs SMART data from its emulated controller and block-accounting state. A guest can therefore show valid-looking SMART without revealing the host drive's health. Guest tests establish guest-path performance; actual physical passthrough and device identity require separate verification. VM coverage cannot establish USB, physical RAID, real wear counters or thermal behavior. [S17]
|
|
||||||
|
|
||||||
Keep ordinary file workloads unprivileged. Device queries may require additional device permissions or kernel capabilities; NVMe's Linux passthrough code explicitly gates classes of commands. A future privileged mechanism should allow only validated read operations and selected devices, with no arbitrary shell or passthrough-command forwarding. Permission denial is an expected capability outcome, not an instruction to run the whole TUI as root. [S18]
|
|
||||||
|
|
||||||
For overall system health, useful complementary evidence is:
|
|
||||||
|
|
||||||
- `/proc/pressure/io`: `some` measures time with some stalled tasks, `full` time with all non-idle tasks stalled; use same-window deltas alongside workload latency. This detects pressure, not its sole cause. [S8]
|
|
||||||
- `/proc/diskstats` or per-device sysfs statistics: completed I/O, time and queue context. Counters have concurrency/accounting caveats; busy percentage alone does not establish NVMe saturation. [S9]
|
|
||||||
- Available hwmon readings, limits and alarm flags: retain sensor identity and units; chip-specific alarms and missing sensors preclude a universal hard-coded temperature cutoff. Standard hwmon ABI readings are intended to be readable by unprivileged applications. [S10]
|
|
||||||
- Kernel errors and existing EDAC/RAS evidence: distinguish corrected errors from uncorrected/fatal errors and report available history. EDAC documentation explicitly says corrected errors may, but need not, predict later uncorrected errors. Missing reporting hardware/driver is unknown. Kernel log access can require `CAP_SYSLOG` when `dmesg_restrict=1`; do not assume systemd/journald on Void or other distributions. [S13][S19]
|
|
||||||
|
|
||||||
Kernel or mount optimizations should be suggestions tied to an observed limitation and a documented tradeoff, recorded for subsequent comparable runs. This research supports observing current settings and thermal/power/error evidence; it supplies no evidence for blanket scheduler, write-cache, governor, or filesystem changes.
|
|
||||||
|
|
||||||
## Remaining decisions and evidence gaps
|
|
||||||
|
|
||||||
The next human decisions are the ordinary run's write authorization/budget, minimum free-space reserve, workload lengths and repetitions, required versus optional queued/sync/verification tests, how reduced-capability results affect score eligibility, the supported transport list, the privilege interaction, and the exact advice wording. A sustained-media profile would need a separate impact budget.
|
|
||||||
|
|
||||||
Implementation work will need parser fixtures from supported smartctl/nvme-cli versions; success, partial and denied-permission results; real ATA/NVMe/USB/RAID samples; healthy and failing vendor examples; and proof of cancellation, space reservation, direct-I/O handling and cleanup across filesystems. No such hardware validation occurred here. No calibrated cross-device replacement thresholds or modern SSD remaining-life model were found or claimed.
|
|
||||||
|
|
||||||
Context7 library resolution succeeded for fio, smartmontools, nvme-cli, Linux kernel, GNU Coreutils and QEMU. Both allowed nvme-cli documentation fetches returned “Could not fetch documentation snippets”; its official released documents and source were inspected instead. The NVM Express specifications landing page returned HTTP 403, so NVMe field semantics here are grounded in maintained libnvme definitions and smartmontools implementation rather than a directly retrieved current specification PDF. Those are material evidence limits, not silently filled gaps.
|
|
||||||
|
|
||||||
## Sources inspected
|
|
||||||
|
|
||||||
- **S1:** [fio 3.43 HOWTO](https://github.com/axboe/fio/blob/fio-3.43/HOWTO.rst), relevant workload, size/runtime, buffering, engines, percentile, verification and error sections; [release](https://github.com/axboe/fio/releases/tag/fio-3.43).
|
|
||||||
- **S2:** [smartctl manual source](https://github.com/smartmontools/smartmontools/blob/master/smartmontools/smartctl.8.in), health, attributes, JSON, exit status, device transports, standby and self-tests.
|
|
||||||
- **S3:** nvme-cli v3.1 [SMART log command](https://github.com/linux-nvme/nvme-cli/blob/v3.1/Documentation/nvme-log-smart.txt), [global options](https://github.com/linux-nvme/nvme-cli/blob/v3.1/Documentation/global-options.txt), [legacy alias](https://github.com/linux-nvme/nvme-cli/blob/master/Documentation/nvme-smart-log.txt), and [release](https://github.com/linux-nvme/nvme-cli/releases/tag/v3.1).
|
|
||||||
- **S4:** [smartmontools NVMe support examples](https://www.smartmontools.org/wiki/NVMe_Support), inspected through Context7.
|
|
||||||
- **S5:** [libnvme types](https://github.com/linux-nvme/libnvme/blob/master/src/nvme/types.h), `nvme_smart_log` and `nvme_smart_crit` documentation.
|
|
||||||
- **S6:** [smartmontools NVMe JSON implementation](https://github.com/smartmontools/smartmontools/blob/master/smartmontools/nvmeprint.cpp).
|
|
||||||
- **S7:** [Linux man-pages open(2)](https://man7.org/linux/man-pages/man2/open.2.html), exclusive creation and direct/synchronized I/O.
|
|
||||||
- **S8:** [Linux PSI documentation](https://www.kernel.org/doc/html/latest/accounting/psi.html).
|
|
||||||
- **S9:** [Linux I/O statistics documentation](https://www.kernel.org/doc/html/latest/admin-guide/iostats.html).
|
|
||||||
- **S10:** [Linux hwmon sysfs interface](https://www.kernel.org/doc/html/latest/hwmon/sysfs-interface.html).
|
|
||||||
- **S11:** [Linux tmpfs documentation](https://docs.kernel.org/filesystems/tmpfs.html).
|
|
||||||
- **S12:** [Linux VM sysctl documentation](https://docs.kernel.org/admin-guide/sysctl/vm.html), `drop_caches`.
|
|
||||||
- **S13:** [Linux RAS documentation source](https://www.kernel.org/doc/html/latest/_sources/admin-guide/RAS/main.rst.txt), error categories and EDAC.
|
|
||||||
- **S14:** [GNU Coreutils dd manual](https://www.gnu.org/software/coreutils/manual/html_node/dd-invocation.html).
|
|
||||||
- **S15:** [smartmontools drive database](https://github.com/smartmontools/smartmontools/blob/master/smartmontools/drivedb.h), default and model-dependent attribute mappings.
|
|
||||||
- **S16:** [Google, Failure Trends in a Large Disk Drive Population](https://research.google/pubs/failure-trends-in-a-large-disk-drive-population/), primary publication abstract, 2007.
|
|
||||||
- **S17:** [QEMU NVMe implementation](https://github.com/qemu/qemu/blob/master/hw/nvme/ctrl.c), `nvme_smart_info`; [NVMe device documentation](https://github.com/qemu/qemu/blob/master/docs/system/devices/nvme.rst), inspected through Context7.
|
|
||||||
- **S18:** [Linux NVMe ioctl authorization](https://github.com/torvalds/linux/blob/master/drivers/nvme/host/ioctl.c).
|
|
||||||
- **S19:** [Linux kernel sysctl documentation](https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html), `dmesg_restrict`.
|
|
||||||
Reference in New Issue
Block a user