forgo.cloud
Sign in
Repo workspace

forkjoin-ai/gnosis

Resonance Knot — Phase 2 Module Contracts

distributed-inference/RKNOT_PHASE2_CONTRACTS.md
forkjoin-ai/gnosis

Resonance Knot — Phase 2 Module Contracts

Six modules, dispatched in parallel. Each subagent writes one file. The existing Phase 1 modules (format, manifest, encoder, decoder, writer, reader, calibration, bitwise_pack) are SSOT — read them before writing.

Phase 2 goal

Take real dense .knot weights → derive real spectral manifests → encode against those manifests → measure file shrinkage and round-trip correctness on a real Llama-shaped model. ASAP-mode: skip the live attention probe and use weight-magnitude statistics to derive the manifest. Phase 3 (later) wires the real attention tap.

Module 1 — src/rknot/dense_reader.rs

Owner: subagent-1. Imports: super::format::*, crate::loader::{read_knot_metadata, TensorInfo, KnotConfig}, std::fs::File, std::io::{Read, Seek, SeekFrom}.

use super::format::*;

#[derive(Debug)]
pub enum DenseReadError {
    Io(std::io::Error),
    KnotLoader(String),
    UnsupportedQuantType(String),
    TensorNotFound(String),
    DimensionMismatch { tensor: String, expected: (u32, u32), got: usize },
}

/// Wraps an existing dense `.knot` file. Constructor parses the
/// metadata; tensors are loaded on demand to avoid holding the whole
/// 40 GB Llama-70B in memory.
pub struct DenseKnotReader {
    file: std::fs::File,
    pub config: KnotConfig,
    pub tensors: std::collections::HashMap<String, TensorInfo>,
    /// Body origin: byte offset in the file where the tensor payload
    /// region begins (after magic + version + meta_len + meta_json).
    body_origin: u64,
}

impl DenseKnotReader {
    pub fn open(path: &std::path::Path) -> Result<Self, DenseReadError>;

    /// Load a single tensor by name into a DenseTensor.
    /// Dequantizes from Q4_K_M / Q5_K_M / Q6_K / Q8_0 / fp16 / fp32 to fp32.
    /// Phase 2 ASAP: support fp16 and fp32 only — punt on K-quant
    /// dequantization (return UnsupportedQuantType for now). The
    /// existing `loader.rs` has the K-quant decoder we can lift later.
    pub fn load_tensor(&mut self, name: &str, expected_rows: u32, expected_cols: u32)
        -> Result<DenseTensor, DenseReadError>;

    /// Convenience: load Q/K/V/FFN_gate/FFN_up/FFN_down for a given layer.
    /// Tensor naming follows the gguf convention (e.g.
    /// "blk.0.attn_q.weight"). Returns the four blocks needed by the
    /// encoder pipeline.
    pub fn load_layer_blocks(&mut self, layer_idx: u32)
        -> Result<LayerTensors, DenseReadError>;
}

pub struct LayerTensors {
    pub q: DenseTensor,
    pub k: DenseTensor,
    pub v: DenseTensor,
    pub ffn: DenseTensor,  // For Phase 2, ffn_gate suffices as the representative
}

Tests:

  • open_rejects_bad_magic — non-KNOT file returns error
  • tensor_offsets_within_file — every TensorInfo offset + length stays inside file size
  • load_tensor_dimension_check — wrong expected dimensions returns DimensionMismatch
  • unsupported_quant_returns_error — Q4_K_M tensor returns UnsupportedQuantType (until Phase 3 lifts the decoder)

Module 2 — src/rknot/manifest_real.rs

Owner: subagent-2. Imports: super::format::*.

Phase 2 ASAP: derive standing-wave dimensions from per-column L2 magnitude statistics on the dense weight matrices, instead of running a live attention probe. This is a defensible proxy — high-magnitude columns ARE the resonant dimensions in the trained network's basis.

use super::format::*;

/// Compute per-column L2 magnitudes. Returns vec of length `tensor.cols`.
pub fn column_magnitudes(tensor: &DenseTensor) -> Vec<f32>;

/// Derive a SpectralManifest by selecting the top `coverage × d`
/// columns by L2 magnitude across Q/K/V combined.
pub fn manifest_from_weight_magnitudes(
    q: &DenseTensor,
    k: &DenseTensor,
    v: &DenseTensor,
    coverage: f32,
) -> SpectralManifest;

/// Compute the energy fraction captured by the standing dimensions —
/// useful as a sanity check ("did we actually pick the load-bearing dims?").
/// Returns ratio in [0, 1]: sum of squared L2 in standing dims / total.
pub fn standing_energy_fraction(
    tensor: &DenseTensor,
    manifest: &SpectralManifest,
) -> f32;

Tests:

  • column_magnitudes_returns_correct_length
  • magnitudes_pick_largest_for_unimodal_input — synthetic tensor with one dominant column → manifest selects it
  • coverage_clamped — coverage > 1 caps at d
  • energy_fraction_is_one_for_full_coverage

Module 3 — src/rknot/bitwise_fp48.rs

Owner: subagent-3. Imports: super::format::QuantBlock.

Replace the stub RLE in bitwise_pack.rs with real fp48-style splitting. Pattern from feedback_bw_dimensional_decomposition (memory): "fp48 splits bytes: vent (low-48 payload) + parity/index (high-16). Dict k -> k*3 makes wire 1/3."

For a payload of n-bit codes:

  • Lifted bits (low-N): the value itself
  • Contracted bits (high-N): a small index over a per-block codebook of recurring value patterns

Phase 2 ASAP: implement a simple variant — group consecutive bytes into 8-byte words, find the top 16 most common 8-byte words in the payload, replace each occurrence with a 4-bit codebook index + escape literal for misses. This captures the "shape regularity" bonus without requiring the full fp48 implementation.

use super::format::QuantBlock;

#[derive(Debug, Clone)]
pub struct Fp48Packed {
    pub codebook: Vec<[u8; 8]>,  // up to 16 entries
    pub indices: Vec<u8>,         // 4-bit codebook indices (LSB first), packed
    pub literals: Vec<u8>,        // raw bytes for non-codebook entries
}

pub fn fp48_pack(payload: &[u8]) -> Fp48Packed;
pub fn fp48_unpack(packed: &Fp48Packed) -> Vec<u8>;

/// Compare raw payload bytes vs fp48-packed total bytes. Returns ratio.
pub fn fp48_bonus_ratio(payload: &[u8]) -> f32;

Tests:

  • pack_unpack_round_trip
  • bonus_at_least_one_on_constant_payload — repeated 8-byte pattern packs to ~1 codebook entry + many indices
  • bonus_below_one_OK_on_high_entropy — random payload may not benefit but must round-trip

Module 4 — src/bin/encode-rknot.rs (v2)

Owner: subagent-4.

Extend the existing Phase 1 binary with an --input <dense.knot> mode that uses Module 1 (dense_reader) + Module 2 (manifest_real) together. Keep the --synthetic mode working for benchmarks.

CLI additions:

encode-rknot --input <path-to-dense.knot> --output <path-to.rknot> \
  --target-k 0.30 --bits-qk 4 --bits-v 8 --bits-ffn 4 \
  --layer-range 0..80         # optional, for partial encodes

For each layer in range:

  1. dense_reader.load_layer_blocks(idx)LayerTensors
  2. manifest_from_weight_magnitudes(&q, &k, &v, target_k) → real manifest
  3. encode_tensor for Q/K/V; encode_ffn_tensor for FFN
  4. Optionally: wrap each block payload through fp48_pack for the bonus
  5. Build ResonanceKnotLayer, push into Rknot.layers

After all layers: writer::write_rknot_to_file. Print summary with real-vs-stub manifest comparison (energy fraction, etc.).

If the input dense.knot has Q-quant tensors (UnsupportedQuantType), fail with a clear error message pointing at Phase 3 where K-quant dequant lands.

Module 5 — src/bin/verify-rknot.rs

Owner: subagent-5.

New binary: round-trip a .rknot against the original dense .knot, measure per-layer quantization error and per-block energy preservation. Lays the groundwork for the Phase 4 "Paris" probe (which needs inference, not just bit-comparison).

//! verify-rknot — round-trip diagnostic for Resonance Knot files
//!
//! Usage:
//!   verify-rknot --rknot <path.rknot> --dense <path.knot> \
//!     [--max-layers 5]
//!
//! For each layer:
//!   1. Load dense Q/K/V/FFN from the original .knot
//!   2. Load .rknot manifest + blocks for the same layer
//!   3. Decode .rknot blocks back to dense (zero-padded to d×d)
//!   4. Compute per-block: max abs error, mean abs error, energy ratio
//!      (sum |decoded|² / sum |original|² restricted to standing dims)
//!   5. Print per-layer table; warn on layers where energy < 0.95

Cargo.toml: add [[bin]] name = "verify-rknot" path = "src/bin/verify-rknot.rs".

Module 6 — cloudbuild-llama-70b-to-rknot.yaml

Owner: subagent-6.

New cloudbuild yaml that:

  1. Reuses the dense .knot already in R2 (skip HF download / dense encode — the existing pipeline produces it)
  2. Adds a repack-rknot step that runs the Rust encode-rknot binary with --input mode
  3. Uploads the resulting .rknot to R2 alongside the dense .knot
  4. Verifies the .rknot via the new verify-rknot binary
# cloudbuild-llama-70b-to-rknot.yaml
#
# Repacks the existing dense .knot from R2 into a Resonance Knot.
# Assumes cloudbuild-llama-70b-to-knot.yaml has already run and
# produced s3://distributed-inference/models/llama-70b.knot.

Steps:

  • fetch-dense-knot — download from R2 to /workspace/llama-70b.knot
  • build-encodercargo build --release --bin encode-rknot --bin verify-rknot
  • encode-rknot — run encoder, produce /workspace/llama-70b.rknot
  • verify-rknot — round-trip diagnostic
  • upload-rknot — multi-part PUT to R2 at models/llama-70b.rknot
  • purge-cdn — best-effort
  • verify-range — first 6 bytes == "RKNOT\x02"

Anchors

After 6 modules land:

  • Phase 2 modules wired into src/rknot/mod.rs: pub mod {dense_reader, manifest_real, bitwise_fp48};
  • Cargo.toml: two new [[bin]] entries (encode-rknot v2 same path, verify-rknot new)
  • cloudbuild-llama-70b-to-rknot.yaml at repo root
  • All tests pass: cargo test --lib rknot::
  • Smoke: encode-rknot --synthetic still works
  • Smoke: verify-rknot prints something sane on the synthetic .rknot

Common pitfalls

  • Existing loader.rs::read_knot_metadata already exists — reuse it, don't reinvent
  • K-quant dequant is non-trivial — punt to Phase 3, fail loudly on it
  • u64 for body offsets, u32 for tensor dims (4 GB tensor cap is fine)
  • #[serde(skip)] on QuantBlock.payload — body lives separately
  • No new crate dependencies — only what's already in Cargo.toml