Skip to content

Design: KeyForge Core

Responsibility: Pure orchestration and helper functions. Tier: 2 (The Glue) Constraint: NO IO allowed. This crate must compile to WASM.

1. Overview

keyforge-core exists to prevent circular dependencies between physics, evolution, and model. It provides high-level functions that coordinate these lower-level crates without being tied to IO or protocols.

graph TD
    Core[keyforge-core]
    Physics[keyforge-physics]
    Evolution[keyforge-evolution]
    Model[keyforge-model]

    Core --> Physics
    Core --> Evolution
    Core --> Model
    Physics --> Model
    Evolution --> Physics
    Evolution --> Model

2. Public API

Engine-Based Functions (Preferred)

Use these when you have a pre-compiled ScoringEngine:

Function Purpose
build_engine(EngineRequest) Compile a new ScoringEngine
score_with_engine(engine, layout) Score a layout → f32
analyze_with_engine(engine, layout) Analyze a layout → AnalysisReport
suggest_with_engine(engine, layout) Get swap suggestions
optimize_with_engine(engine, config, callback, ...) Run optimization
identify(layout) Match to known layout (Qwerty, etc.)

Request-Based Functions (Legacy)

These compile an engine internally from an EngineRequest:

Function Purpose
score(EngineRequest) Score → OptimizationResult
analyze(EngineRequest) Analyze → AnalysisReport
suggest(EngineRequest) Suggest swaps
optimize(EngineRequest) Optimize without callback
optimize_with_callback(EngineRequest, CB) Optimize with progress

3. ScoringSession

A consolidated environment holding a compiled engine with metadata:

classDiagram
    class ScoringSession {
        +Arc~dyn ScoringEngine~ engine
        +Arc~KeycodeRegistry~ registry
        +SearchConfig search_config
        +new(engine, registry, config) ScoringSession
    }

    class ScoringEngine {
        <<trait>>
    }

    class KeycodeRegistry {
        +get_code(label) Option~KeyCode~
        +get_label(code) Option~&str~
    }

    ScoringSession --> ScoringEngine
    ScoringSession --> KeycodeRegistry

4. AssetLoader Trait

The IO abstraction allowing core to remain filesystem/network agnostic:

classDiagram
    class AssetLoader {
        <<trait>>
        +load~T: Asset~(id: &str) LoaderResult~Arc~T~~
        +load_corpus(sources: &[CorpusSource]) LoaderResult~Arc~Corpus~~
    }

    class Asset {
        <<trait>>
        +category() AssetCategory
    }

    AssetLoader ..> Asset : loads

Implementations live in keyforge-infra (filesystem) and keyforge-wasm (in-memory).

5. Optimization Flow

sequenceDiagram
    participant Client
    participant Core
    participant Physics as dyn ScoringEngine
    participant Evo as Evolution

    Client->>Core: optimize_with_engine(engine, config, callback, ...)
    Core->>Evo: evolve(engine, config, callback, ...)

    loop Annealing Steps
        Evo->>Physics: calculate_swap_delta()
        Physics-->>Evo: delta (i64)
        Evo->>Evo: accept/reject

        opt Epoch Boundary
            Evo->>Client: callback.on_progress(epoch, score, layout, ips)
            Client-->>Evo: OptimizationControl
        end
    end

    Evo-->>Core: OptimizationResult
    Core-->>Client: Result

6. Re-exports

For convenience, keyforge-core re-exports commonly used types:

From Types
keyforge-evolution EvolutionError, ProgressCallback
keyforge-physics ScoringEngine, PhysicsError, EngineRequest, LayoutIdentity, DeterministicScorer

7. Module Structure

keyforge-core/src/
├── loader.rs    # AssetLoader trait, LoaderResult
├── session.rs   # ScoringSession
└── lib.rs       # Public API functions, re-exports