Skip to content

pkg/mutator

Structure-aware GGUF mutation.

import "github.com/professor-moody/crucible/pkg/mutator"

Strategy

type Strategy interface {
    Name() string
    Mutate(f *gguf.File, rng *rand.Rand)
}

rand.Rand is from math/rand/v2. Optional interfaces alter serialization:

  • PaddingSkipper requests serialization without alignment padding.
  • CountKeeper prevents automatic header-count synchronization.

Mutator

func New(seed uint64) *Mutator
func NewWithProfile(seed uint64, p Profile) *Mutator

A non-zero seed gives a deterministic strategy sequence for the same inputs and call order. Zero seeds from runtime randomness.

func (m *Mutator) Mutate(f *gguf.File) ([]byte, error)
func (m *Mutator) MutateBytes(data []byte) ([]byte, error)
func (m *Mutator) AppliedMutations(f *gguf.File) ([]byte, []string, error)
func (m *Mutator) CrossOver(data1, data2 []byte) ([]byte, error)

Mutate and AppliedMutations select one to three strategies. Unless a selected strategy is a CountKeeper, they call SyncCounts before MarshalRaw. MutateBytes returns a parse error for non-GGUF input; the libFuzzer archive handles that error by delegating to byte mutation.

CrossOver parses both inputs, combines structural components, applies a mutation, and serializes the result.

Categories

Constant Default weight
CategoryHeader 10%
CategoryMetadata 35%
CategoryTensorInfo 35%
CategoryAlignment 5%
CategoryData 5%
CategoryConsistency 10%

Model-loader strategies are registered in the metadata category.

Factories:

func HeaderStrategies() []Strategy
func MetadataStrategies() []Strategy
func TensorInfoStrategies() []Strategy
func AlignmentStrategies() []Strategy
func DataStrategies() []Strategy
func ConsistencyStrategies() []Strategy
func ModelLoaderStrategies() []Strategy

Introspection:

func CategoryNamePrefixes() map[Category][]string
func DefaultCategoryWeightsByName() map[string]float64

Built-in profiles:

func TunedGGUFProfile() Profile
func CrossoverLeanProfile() Profile

Profiles are additive filters and weight overrides; inspect Profile in profile.go for the current fields.

Example

seed := uint64(42)
m := mutator.New(seed)

input, err := os.ReadFile("seed.gguf")
if err != nil {
    log.Fatal(err)
}
output, err := m.MutateBytes(input)
if err != nil {
    log.Fatal(err)
}
if err := os.WriteFile("mutated.gguf", output, 0o644); err != nil {
    log.Fatal(err)
}

See Mutation Strategies for registered names.