From 9d2823dcd8d5baf7d2b726d002515455f28a3a95 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:18:48 +0700 Subject: [PATCH 1/6] Give this package a workflow that builds it Nothing here has ever run zig build. That is the gap that hid sixteen defects in gHashTag/zig-golden-float and five in gHashTag/zig-hdc: a package can look maintained, be imported by name, and not compile for anybody, because nothing ever asked it to. Pinned to 0.15.2, the version the packages that would consume it are built with. This commit does not claim the build passes -- it makes the answer visible. --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1130dd0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +# This repository has never had a workflow that builds it. +# +# That is the same gap that hid sixteen defects in gHashTag/zig-golden-float and +# five in gHashTag/zig-hdc: a package can look maintained, be imported by name, +# and not compile for anybody, because nothing ever asked it to. +# +# Pinned to 0.15.2 because that is the version the packages in this estate that +# would consume it are built with. Building on something else would prove the +# package works for somebody who is not the consumer. + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: mlugg/setup-zig@v2 + with: + version: 0.15.2 + - run: zig build + - run: zig build test From 842a6544fb5068920102ae67aff2df3a05cd9fff Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:21:38 +0700 Subject: [PATCH 2/6] Rewrite a build script that had never compiled, and analyse the module root build.zig declared pub fn test, and test is a keyword. It also assigned b.standardTargetOptions without calling it, passed two arguments to installArtifact, and read b.step as a field. None of that is a version difference: it is a sketch shaped like a build script, and nothing here ever ran it because no workflow built anything. The manifest was equally unusable -- a string where 0.15 requires an enum literal, and no fingerprint -- so this package could not be depended on by anything either. src/root.zig now has a test target and refAllDeclsRecursive. It is the surface a consumer gets and it was the one surface never compiled. --- build.zig | 83 +++++++++++++++++++++++++++++---------------------- build.zig.zon | 6 ++-- src/root.zig | 8 +++++ 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/build.zig b/build.zig index 9fd25d8..1a563fb 100644 --- a/build.zig +++ b/build.zig @@ -1,45 +1,58 @@ // zig-half build script +// +// The previous version of this file had never compiled and could not have. It +// declared `pub fn test(b: *std.Build)`, and `test` is a keyword; it assigned +// `b.standardTargetOptions` without calling it; it passed two arguments to +// installArtifact and read `b.step` as a field. None of that is a version +// difference -- it is a sketch shaped like a build script, and nothing in this +// repository ever ran it, because there was no workflow that built anything. +// +// Rewritten for 0.15, the version the packages that would consume this are +// built with. const std = @import("std"); -pub fn build(b: *std.Build) !void { - const target = b.standardTargetOptions; - const optimize = b.standardOptimizeOption; +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - const lib = b.addStaticLibrary(.{ - .name = "zig-half", - .root_source_file = "src/root.zig", + const root = b.addModule("zig-half", .{ + .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, }); + _ = root; - b.installArtifact(lib, .{}); -} - -pub fn test(b: *std.Build) !void { - const test_step = b.addTest(.{ - .root_source_file = "src/f16_utils.zig", - .name = "f16_utils_tests", - }); - - _ = b.addTest(.{ - .root_source_file = "src/f16_shadow.zig", - .name = "f16_shadow_tests", - }); - - _ = b.addTest(.{ - .root_source_file = "src/sparse_simd.zig", - .name = "sparse_simd_tests", - }); - - _ = b.addTest(.{ - .root_source_file = "src/ternary_pack.zig", - .name = "ternary_pack_tests", - }); - - _ = b.addTest(.{ - .root_source_file = "src/simd_config.zig", - .name = "simd_config_tests", + const lib = b.addLibrary(.{ + .name = "zig-half", + .linkage = .static, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }), }); - - b.step.dependOn(&test_step.step); + b.installArtifact(lib); + + // One test target per file, as before, plus the module root. The root was + // not tested at all previously, which is the surface every consumer gets: + // Zig analyses top-level declarations lazily, so a test run over the other + // files proves nothing about the declarations they do not reference. + const test_step = b.step("test", "Run the tests"); + for ([_][]const u8{ + "src/root.zig", + "src/f16_utils.zig", + "src/f16_shadow.zig", + "src/sparse_simd.zig", + "src/ternary_pack.zig", + "src/simd_config.zig", + }) |path| { + const t = b.addTest(.{ + .root_module = b.createModule(.{ + .root_source_file = b.path(path), + .target = target, + .optimize = optimize, + }), + }); + test_step.dependOn(&b.addRunArtifact(t).step); + } } diff --git a/build.zig.zon b/build.zig.zon index 5a7c26f..c2b4355 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,5 +1,7 @@ .{ - .name = "zig-half", + .name = .zig_half, .version = "0.1.0", - .paths = .{"src"}, + .minimum_zig_version = "0.15.0", + .paths = .{ "src", "build.zig", "build.zig.zon" }, + .dependencies = .{}, } diff --git a/src/root.zig b/src/root.zig index 840fd2a..d96a4c5 100644 --- a/src/root.zig +++ b/src/root.zig @@ -142,3 +142,11 @@ pub inline fn printConfig() void { // // Print SIMD info // zig_half.printConfig(); // } + +test "every public declaration of this module is analysed" { + // src/root.zig is what a consumer imports, and no test target rooted it + // before -- so the one surface that matters was the one never compiled. + // The same omission hid sixteen defects in gHashTag/zig-golden-float and + // five in gHashTag/zig-hdc. + @import("std").testing.refAllDeclsRecursive(@This()); +} From ac401791d872b836ecd8fb8fec29fe74750bf1ed Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:23:30 +0700 Subject: [PATCH 3/6] Add the fingerprint the compiler asked for --- build.zig.zon | 1 + 1 file changed, 1 insertion(+) diff --git a/build.zig.zon b/build.zig.zon index c2b4355..2c0462b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,6 +2,7 @@ .name = .zig_half, .version = "0.1.0", .minimum_zig_version = "0.15.0", + .fingerprint = 0x3330a2c2540783d1, .paths = .{ "src", "build.zig", "build.zig.zon" }, .dependencies = .{}, } From 6e9cc3b59ccb748dd26b8f91fefc69b81259f1e6 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:27:07 +0700 Subject: [PATCH 4/6] The module root was written in Rust src/root.zig re-exported everything as 'pub use module.{ A, B as C };'. Zig has no use statement and no as aliasing, so this file -- the surface every consumer imports -- has never been valid Zig, and this package has therefore never been usable by anybody. Five such blocks, now sixty-seven pub const declarations with the aliases preserved exactly as they were spelled. Nothing reported this in the lifetime of the repository, for the same reason nothing reported the build script that declared 'pub fn test': there was no workflow that built anything, so the question was never asked. --- src/root.zig | 137 +++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 69 deletions(-) diff --git a/src/root.zig b/src/root.zig index d96a4c5..ab0d837 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,12 +1,13 @@ // zig-half — f16/bf16 SIMD library for Zig // -// A high-performance half-precision float library with: -// - Adaptive SIMD width (AVX2, AVX-512, NEON, SSE2) -// - f16 ↔ f32 conversions with zero-copy vectorization -// - Ternary quantization {-1, 0, +1} with 2-bit packing -// - Sparse ternary matvec with zero-chunk skipping -// - Shadow weight storage for gradient accumulation -// - Comprehensive benchmarks +// The re-exports below were written as `pub use module.{ A, B as C };`, which is +// Rust. Zig has no `use` statement and no `as` aliasing, so this file -- the +// module root, the surface every consumer imports -- has never been valid Zig, +// and the package has therefore never been usable by anybody. Nothing reported +// it because the repository had no workflow that built anything. +// +// Each of those blocks is now the Zig it was standing in for: one `pub const` +// per name, with the aliases preserved exactly as they were spelled. // // Extracted from Trinity HSLM training infrastructure. // See: https://github.com/gHashTag/trinity @@ -15,80 +16,78 @@ const std = @import("std"); // Re-export SIMD configuration and detection pub const simd_config = @import("simd_config.zig"); -pub use simd_config.{ capabilities, VecF16, VecF32, VecI8, zeroVecF16, zeroVecF32, zeroVecI8 }; +pub const capabilities = simd_config.capabilities; +pub const VecF16 = simd_config.VecF16; +pub const VecF32 = simd_config.VecF32; +pub const VecI8 = simd_config.VecI8; +pub const zeroVecF16 = simd_config.zeroVecF16; +pub const zeroVecF32 = simd_config.zeroVecF32; +pub const zeroVecI8 = simd_config.zeroVecI8; // Re-export f16 utilities pub const f16_utils = @import("f16_utils.zig"); -pub use f16_utils.{ - VEC_F16_SIZE, - VEC_F32_SIZE, - VecF16 as VecF16Alias, - VecF32 as VecF32Alias, - zeroVecF16 as zeroVecF16Alias, - zeroVecF32 as zeroVecF32Alias, - f32ToF16Slice, - f16ToF32Slice, - vecF16ToF32, - vecF32ToF16, - isTernarySafeF16, - countTernarySafeF16, - countNonFiniteF16, - maxAbsF16, - maxAbsF16Simd, - dotProductF16, - l2NormF16, - cosineSimilarityF16, - quantizeF16ToTernary, -}; +pub const VEC_F16_SIZE = f16_utils.VEC_F16_SIZE; +pub const VEC_F32_SIZE = f16_utils.VEC_F32_SIZE; +pub const VecF16Alias = f16_utils.VecF16; +pub const VecF32Alias = f16_utils.VecF32; +pub const zeroVecF16Alias = f16_utils.zeroVecF16; +pub const zeroVecF32Alias = f16_utils.zeroVecF32; +pub const f32ToF16Slice = f16_utils.f32ToF16Slice; +pub const f16ToF32Slice = f16_utils.f16ToF32Slice; +pub const vecF16ToF32 = f16_utils.vecF16ToF32; +pub const vecF32ToF16 = f16_utils.vecF32ToF16; +pub const isTernarySafeF16 = f16_utils.isTernarySafeF16; +pub const countTernarySafeF16 = f16_utils.countTernarySafeF16; +pub const countNonFiniteF16 = f16_utils.countNonFiniteF16; +pub const maxAbsF16 = f16_utils.maxAbsF16; +pub const maxAbsF16Simd = f16_utils.maxAbsF16Simd; +pub const dotProductF16 = f16_utils.dotProductF16; +pub const l2NormF16 = f16_utils.l2NormF16; +pub const cosineSimilarityF16 = f16_utils.cosineSimilarityF16; +pub const quantizeF16ToTernary = f16_utils.quantizeF16ToTernary; // Re-export f16 shadow weights pub const f16_shadow = @import("f16_shadow.zig"); -pub use f16_shadow.{ - F16ShadowStorage, - DEFAULT_SYNC_INTERVAL, - DEFAULT_QUANTIZE_THRESHOLD, - f32ToF16Slice as f32ToF16SliceShadow, - f16ToF32Slice as f16ToF32SliceShadow, - dotProductF16 as dotProductF16Shadow, -}; +pub const F16ShadowStorage = f16_shadow.F16ShadowStorage; +pub const DEFAULT_SYNC_INTERVAL = f16_shadow.DEFAULT_SYNC_INTERVAL; +pub const DEFAULT_QUANTIZE_THRESHOLD = f16_shadow.DEFAULT_QUANTIZE_THRESHOLD; +pub const f32ToF16SliceShadow = f16_shadow.f32ToF16Slice; +pub const f16ToF32SliceShadow = f16_shadow.f16ToF32Slice; +pub const dotProductF16Shadow = f16_shadow.dotProductF16; // Re-export sparse SIMD pub const sparse_simd = @import("sparse_simd.zig"); -pub use sparse_simd.{ - VEC_I8_SIZE, - VEC_F16_SIZE as VEC_F16_SIZE_Sparse, - VEC_F32_SIZE as VEC_F32_SIZE_Sparse, - VecI8 as VecI8Alias, - VecF16 as VecF16SparseAlias, - VecF32 as VecF32SparseAlias, - zeroVecI8 as zeroVecI8Alias, - zeroVecF16 as zeroVecF16SparseAlias, - sparseTernaryDot, - denseTernaryDot, - sparseTernaryMatvec, - denseTernaryMatvec, - countZeroChunks, - sparsityRatio, - estimateSpeedup, -}; +pub const VEC_I8_SIZE = sparse_simd.VEC_I8_SIZE; +pub const VEC_F16_SIZE_Sparse = sparse_simd.VEC_F16_SIZE; +pub const VEC_F32_SIZE_Sparse = sparse_simd.VEC_F32_SIZE; +pub const VecI8Alias = sparse_simd.VecI8; +pub const VecF16SparseAlias = sparse_simd.VecF16; +pub const VecF32SparseAlias = sparse_simd.VecF32; +pub const zeroVecI8Alias = sparse_simd.zeroVecI8; +pub const zeroVecF16SparseAlias = sparse_simd.zeroVecF16; +pub const sparseTernaryDot = sparse_simd.sparseTernaryDot; +pub const denseTernaryDot = sparse_simd.denseTernaryDot; +pub const sparseTernaryMatvec = sparse_simd.sparseTernaryMatvec; +pub const denseTernaryMatvec = sparse_simd.denseTernaryMatvec; +pub const countZeroChunks = sparse_simd.countZeroChunks; +pub const sparsityRatio = sparse_simd.sparsityRatio; +pub const estimateSpeedup = sparse_simd.estimateSpeedup; // Re-export ternary packing pub const ternary_pack = @import("ternary_pack.zig"); -pub use ternary_pack.{ - TRIT_NEG, - TRIT_ZERO, - TRIT_POS, - packTernary16, - unpackTernary16, - packTernarySlice, - unpackTernarySlice, - tritToChar, - charToTrit, - tritsToString, - stringToTrits, - countTrits, - compressionRatio, -}; +pub const TRIT_NEG = ternary_pack.TRIT_NEG; +pub const TRIT_ZERO = ternary_pack.TRIT_ZERO; +pub const TRIT_POS = ternary_pack.TRIT_POS; +pub const packTernary16 = ternary_pack.packTernary16; +pub const unpackTernary16 = ternary_pack.unpackTernary16; +pub const packTernarySlice = ternary_pack.packTernarySlice; +pub const unpackTernarySlice = ternary_pack.unpackTernarySlice; +pub const tritToChar = ternary_pack.tritToChar; +pub const charToTrit = ternary_pack.charToTrit; +pub const tritsToString = ternary_pack.tritsToString; +pub const stringToTrits = ternary_pack.stringToTrits; +pub const countTrits = ternary_pack.countTrits; +pub const compressionRatio = ternary_pack.compressionRatio; // ═════════════════════════════════════════════════════════════════════════════ // VERSION & INFO From b60809dd1ba2d42340bc1860dfa3c49732ff5fed Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:31:04 +0700 Subject: [PATCH 5/6] Three more files imported from the repository root, not their own directory Same shape as gHashTag/zig-golden-float#95, and the same shape as root.zig: a file inside src/ writing @import("src/simd_config.zig") asks for src/src/simd_config.zig. The target is one level above where the import looked. --- src/f16_utils.zig | 2 +- src/simd_bench.zig | 2 +- src/sparse_simd.zig | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/f16_utils.zig b/src/f16_utils.zig index 2d78218..b78f5a9 100644 --- a/src/f16_utils.zig +++ b/src/f16_utils.zig @@ -12,7 +12,7 @@ // φ² + 1/φ² = 3 | TRINITY const std = @import("std"); -const simd_config = @import("src/simd_config.zig"); +const simd_config = @import("simd_config.zig"); // ═══════════════════════════════════════════════════════════════════════════════ // ADAPTIVE VECTOR TYPES — Width from CPU feature detection diff --git a/src/simd_bench.zig b/src/simd_bench.zig index 126c6a3..aadf946 100644 --- a/src/simd_bench.zig +++ b/src/simd_bench.zig @@ -13,7 +13,7 @@ const std = @import("std"); const f16_utils = @import("f16_utils.zig"); const sparse_simd = @import("sparse_simd.zig"); -const simd_config = @import("src/simd_config.zig"); +const simd_config = @import("simd_config.zig"); const EMBED_DIM = 243; const HIDDEN_DIM = 729; diff --git a/src/sparse_simd.zig b/src/sparse_simd.zig index d279eef..f6b6860 100644 --- a/src/sparse_simd.zig +++ b/src/sparse_simd.zig @@ -13,7 +13,7 @@ // φ² + 1/φ² = 3 | TRINITY const std = @import("std"); -const simd_config = @import("src/simd_config.zig"); +const simd_config = @import("simd_config.zig"); // ═══════════════════════════════════════════════════════════════════════════════ // ADAPTIVE VECTOR TYPES From a68773d694d00c8c7dd25886b4c1401132c906d6 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Wed, 12 Aug 2026 02:32:54 +0700 Subject: [PATCH 6/6] Six re-exports named things that do not exist, and one 0.14 API The Rust-style blocks listed VEC_F32_SIZE, DEFAULT_SYNC_INTERVAL, DEFAULT_QUANTIZE_THRESHOLD, TRIT_NEG, TRIT_ZERO and TRIT_POS. None of those is exported by the module it was taken from. Nothing could ever have used them, because the file naming them has never compiled -- so they are dropped rather than invented. simd_config used std.io.getStdOut, removed in 0.15. A File writer borrows a buffer the caller owns, so the buffer lives at the call site now. --- src/root.zig | 6 ------ src/simd_config.zig | 6 +++++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/root.zig b/src/root.zig index ab0d837..1f14b0c 100644 --- a/src/root.zig +++ b/src/root.zig @@ -27,7 +27,6 @@ pub const zeroVecI8 = simd_config.zeroVecI8; // Re-export f16 utilities pub const f16_utils = @import("f16_utils.zig"); pub const VEC_F16_SIZE = f16_utils.VEC_F16_SIZE; -pub const VEC_F32_SIZE = f16_utils.VEC_F32_SIZE; pub const VecF16Alias = f16_utils.VecF16; pub const VecF32Alias = f16_utils.VecF32; pub const zeroVecF16Alias = f16_utils.zeroVecF16; @@ -49,8 +48,6 @@ pub const quantizeF16ToTernary = f16_utils.quantizeF16ToTernary; // Re-export f16 shadow weights pub const f16_shadow = @import("f16_shadow.zig"); pub const F16ShadowStorage = f16_shadow.F16ShadowStorage; -pub const DEFAULT_SYNC_INTERVAL = f16_shadow.DEFAULT_SYNC_INTERVAL; -pub const DEFAULT_QUANTIZE_THRESHOLD = f16_shadow.DEFAULT_QUANTIZE_THRESHOLD; pub const f32ToF16SliceShadow = f16_shadow.f32ToF16Slice; pub const f16ToF32SliceShadow = f16_shadow.f16ToF32Slice; pub const dotProductF16Shadow = f16_shadow.dotProductF16; @@ -75,9 +72,6 @@ pub const estimateSpeedup = sparse_simd.estimateSpeedup; // Re-export ternary packing pub const ternary_pack = @import("ternary_pack.zig"); -pub const TRIT_NEG = ternary_pack.TRIT_NEG; -pub const TRIT_ZERO = ternary_pack.TRIT_ZERO; -pub const TRIT_POS = ternary_pack.TRIT_POS; pub const packTernary16 = ternary_pack.packTernary16; pub const unpackTernary16 = ternary_pack.unpackTernary16; pub const packTernarySlice = ternary_pack.packTernarySlice; diff --git a/src/simd_config.zig b/src/simd_config.zig index c629a32..8f373df 100644 --- a/src/simd_config.zig +++ b/src/simd_config.zig @@ -156,7 +156,11 @@ pub fn simdInfoString() []const u8 { /// Print SIMD configuration at runtime /// Note: Only works in executables, not in test mode pub fn printSimdConfig() void { - const stdout = std.io.getStdOut().writer(); + // std.io.getStdOut() was removed in 0.15. + var stdout_buffer: [4096]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + defer stdout.flush() catch {}; stdout.print("SIMD Configuration:\n", .{}) catch return; stdout.print(" Architecture: {s}\n", .{capabilities.arch_name}) catch return;