Skip to content

Expose post-run exported-global snapshot + a witness-harness mode (coverage backend for witness MC/DC) #340

Description

@avrabe

Why

witness (MC/DC for Wasm) instruments core modules, adding exported mutable globals __witness_counter_<id>, and reads coverage back by snapshotting those globals after a run. It can do this for cores it runs under its embedded preview1 runtime, but not for Component-Model artifacts (wasm32-wasip2/p3): a component must run through a runtime's component API, and wasmtime's component::Instance gives no way to read the inner core's globals.

kiln is the opportunity here: we own it, it already does Component-Model decode/instantiation + WASI 0.2, it's no_std/deterministic/formally-verified (a certifiable coverage runtime is on-thesis), and it already reads globals internally (kiln-instructions … get_global, kiln-runtime/global.rs). Exposing that outward makes kiln a witness coverage backend — and lets us run the same instrumented artifact under kiln and wasmtime to differentially cross-check (kiln validated against wasmtime as oracle while it matures). Strategy tracked in pulseengine/witness#110.

The ask (concrete)

  1. Post-run exported-global snapshot API. After running a module/component, read the values of exported globals by name (or a snapshot of all __witness_counter_*). The internal machinery exists (get_global by index + export info); this needs an outward, post-run accessor keyed by export name, reachable from a host driver. Return type: name → integer value.

  2. Harness/CLI mode usable by witness. A kilnd invocation (or library entry) that witness's --harness can call: it receives WITNESS_MODULE / WITNESS_MANIFEST / WITNESS_OUTPUT env vars, instantiates + runs the module (invoking the specified export(s)), then writes the counter snapshot (step 1) to WITNESS_OUTPUT in witness's counter-snapshot JSON shape. (Happy to share that shape.)

  3. Coverage-grade imports. For coverage we need imports satisfied only enough that branches execute — functionally-correct WASI is not required; stubbed/no-op wasi:* is acceptable. Flag which wasi:0.2 interfaces are real vs. need stubbing for a syscall-heavy fused core.

Scope / non-goals (for now)

  • p3 async-lift / streams are out of scope here — that's gated on p3 execution maturity (kiln parses stream<>/future<> types but doesn't execute async-lift tasks yet; nobody really does). Tracked separately as witness REQ-057 / witness#107(B).
  • This is about synchronous Component-Model coverage first.

How witness uses it

meld fuse component.wasm -o core.wasm        # leaf/syscall-heavy → single core
witness instrument core.wasm -o inst.wasm    # adds __witness_counter_* globals
witness run inst.wasm --harness 'kilnd …'    # kiln runs it, dumps counters
                                             # witness reconstructs the MC/DC truth tables

Refs: pulseengine/witness#110 (strategy + dual-runtime cross-check), witness DEC-003 (counter mechanism), witness REQ-054/FEAT-034 (meld composition).

🤖 Drafted with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions