Skip to content

Seed Thompson-sampling bandit with informative priors from static target profiling - #1

Merged
daedalus merged 3 commits into
masterfrom
copilot/bayes-theorem-advantage
Jul 15, 2026
Merged

Seed Thompson-sampling bandit with informative priors from static target profiling#1
daedalus merged 3 commits into
masterfrom
copilot/bayes-theorem-advantage

Conversation

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Every mutation operator arm in the Thompson-sampling bandit (MonteCarloScheduler) started from the same uninformative Beta(1, 1) prior, even when static analysis already knows the target's input format (e.g. PNG, gzip) or has extracted dictionary tokens — evidence the bandit would otherwise have to rediscover through executions.

Bandit

  • MonteCarloScheduler.init_arm() accepts optional prior_alpha/prior_beta; defaults unchanged (Beta(1,1))
  • Values clamped via named MIN_BETA_PARAM constant to keep betavariate() sampling stable
  • Added supports_priors capability flag so only Bayesian schedulers accept priors (MOpt/Replicator/Elo use non-Beta internal state and are unaffected)

Static profiling → priors

  • New format_operator_priors() in core/target_profiler.py: derives {operator: (alpha, beta)} overrides
    • Detected format (png/jpeg/gzip/bz2/xz/zlib/riff) boosts matching FORMAT_MUTATIONS operators
    • Extracted magic bytes / boundary markers / interesting strings boost DICT_MUTATIONS operators

Wiring

  • services/fuzzer.py's _register_arms() computes format_operator_priors(self._profile) and passes it through to the bandit only, with defensive validation before unpacking
mc = MonteCarloScheduler()
mc.init_arm("png_chunk_mutate", prior_alpha=2.0, prior_beta=1.0)  # biased toward success pre-evidence
mc.init_arm("bit_flip")  # unchanged default Beta(1, 1)

README updated to document the new prior-derivation behavior under Static Target Analysis.

Summary by Sourcery

Seed the Thompson-sampling scheduler with informative priors derived from static target profiling and wire these priors into scheduler arm registration.

New Features:

  • Derive operator-specific Beta priors from target profiles via format signatures and extracted tokens to guide the Thompson-sampling bandit.
  • Allow the MonteCarloScheduler to accept configurable Beta priors per arm while advertising prior support via a capability flag.
  • Pass static-analysis-derived operator priors into MonteCarloScheduler arm registration during fuzzer initialization.

Enhancements:

  • Clamp Beta prior parameters in MonteCarloScheduler to a small positive minimum to keep sampling numerically stable.
  • Document the new informative prior behavior in the README under static target analysis.

Tests:

  • Add unit tests covering format-to-operator prior mapping, dictionary-operator boosting based on extracted tokens, and validity of generated priors.
  • Add unit tests verifying informative priors, idempotent registration, and parameter clamping behavior in MonteCarloScheduler.init_arm().

@daedalus
daedalus marked this pull request as ready for review July 15, 2026 21:25
Copilot AI review requested due to automatic review settings July 15, 2026 21:25
@daedalus
daedalus merged commit 86278d0 into master Jul 15, 2026
@sourcery-ai

sourcery-ai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces informative Beta priors for the Thompson-sampling MonteCarloScheduler using static target profiling, wires those priors through arm registration for schedulers that support them, and documents and tests the new behavior.

Sequence diagram for registering arms with informative priors

sequenceDiagram
    participant Fuzzer
    participant TargetProfiler
    participant MonteCarloScheduler
    participant MOptScheduler

    Fuzzer->>TargetProfiler: format_operator_priors(profile)
    TargetProfiler-->>Fuzzer: priors

    Fuzzer->>MonteCarloScheduler: _register_arms(scheduler=mc, priors=priors)
    activate MonteCarloScheduler
    MonteCarloScheduler-->>MonteCarloScheduler: supports_priors = True
    MonteCarloScheduler-->>MonteCarloScheduler: init_arm(op, prior_alpha, prior_beta)
    deactivate MonteCarloScheduler

    Fuzzer->>MOptScheduler: _register_arms(scheduler=mopt, priors=priors)
    activate MOptScheduler
    MOptScheduler-->>MOptScheduler: supports_priors (missing or False)
    MOptScheduler-->>MOptScheduler: init_arm(op)
    deactivate MOptScheduler
Loading

File-Level Changes

Change Details Files
Derive informative operator-specific Beta priors from static target profiling data.
  • Add _FORMAT_OPERATOR_HINTS and _DICT_OPERATORS lookup tables to map format signatures and token presence to relevant mutation operators.
  • Introduce _BOOSTED_PRIOR constant representing the favored Beta(2.0, 1.0) prior for hinted operators.
  • Implement format_operator_priors(profile) to return a {operator: (alpha, beta)} mapping based on format_signature and presence of magic_bytes, boundary_markers, or interesting_strings, with empty profile yielding no priors.
src/fuzzer_tool/core/target_profiler.py
Extend MonteCarloScheduler to support configurable, clamped Beta priors per arm and advertise prior capability.
  • Define MIN_BETA_PARAM lower clamp to keep random.betavariate() numerically stable for malformed priors.
  • Add supports_priors = True capability flag to MonteCarloScheduler to signal that init_arm accepts priors.
  • Change init_arm to accept optional prior_alpha/prior_beta parameters, defaulting to 1.0, clamp them via MIN_BETA_PARAM, and preserve existing idempotent behavior by only applying the prior on first registration.
src/fuzzer_tool/core/montecarlo.py
Wire format-derived priors into scheduler arm registration while remaining compatible with non-Bayesian schedulers.
  • Update _register_arms in Fuzzer service to accept an optional priors mapping, check scheduler.supports_priors, and pass (alpha, beta) into init_arm only when appropriate and well-formed.
  • Refactor arm registration to use a local init helper so all operators (MUTATIONS, DICT_MUTATIONS, markov_bytes, cem_bytes, grammar* and FORMAT_MUTATIONS) consistently use priors when available.
  • Compute format_operator_priors(self._profile) once and pass the resulting priors only to the MonteCarloScheduler (mc) while leaving MOpt, Replicator, and Elo registrations unchanged behaviorally.
src/fuzzer_tool/services/fuzzer.py
Add unit tests validating prior derivation and MonteCarloScheduler prior handling.
  • Extend test_target_profiler to import _FORMAT_OPERATOR_HINTS and format_operator_priors and add TestFormatOperatorPriors covering empty profiles, known/unknown formats, token sources (magic_bytes, boundary_markers), and positivity/finite-ness of returned alphas/betas.
  • Extend test_montecarlo to cover informative prior initialization, non-overwriting of priors when re-registering an arm, and clamping of non-positive prior parameters.
tests/test_target_profiler.py
tests/test_montecarlo.py
Document the new informative prior behavior in the README.
  • Add a bullet to the README’s feature list explaining that format_operator_priors seeds the Thompson-sampling bandit’s Beta priors toward structure-aware and dictionary operators when static analysis provides hints, instead of always using the uninformative Beta(1, 1).
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@daedalus
daedalus deleted the copilot/bayes-theorem-advantage branch July 15, 2026 21:25

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • In _register_arms, invalid priors entries (e.g. wrong-length tuples or non-numeric values) are silently ignored and fall back to default behavior; consider adding explicit validation/logging so configuration mistakes are surfaced rather than quietly degraded.
  • When clamping prior_alpha/prior_beta in MonteCarloScheduler.init_arm, you currently modify bad priors silently; adding a debug log (or raising in strict modes) when values are clamped would make it easier to detect misconfigured priors without affecting the default behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_register_arms`, invalid `priors` entries (e.g. wrong-length tuples or non-numeric values) are silently ignored and fall back to default behavior; consider adding explicit validation/logging so configuration mistakes are surfaced rather than quietly degraded.
- When clamping `prior_alpha`/`prior_beta` in `MonteCarloScheduler.init_arm`, you currently modify bad priors silently; adding a debug log (or raising in strict modes) when values are clamped would make it easier to detect misconfigured priors without affecting the default behavior.

## Individual Comments

### Comment 1
<location path="src/fuzzer_tool/core/target_profiler.py" line_range="619-626" />
<code_context>
+
+# Format signature -> structure-aware mutation operators that are almost
+# certainly useful for that format (see core.mutations.FORMAT_MUTATIONS).
+_FORMAT_OPERATOR_HINTS: dict[str, tuple[str, ...]] = {
+    "png": ("png_chunk_mutate", "png_crc_fix"),
+    "jpeg": ("jpeg_chunk_mutate", "jpeg_crc_fix"),
+    "gzip": ("gzip_chunk_mutate",),
+    "bz2": ("gzip_chunk_mutate",),
+    "xz": ("gzip_chunk_mutate",),
+    "zlib": ("zlib_chunk_mutate",),
+    "riff": ("bmp_chunk_mutate",),
+}
+
</code_context>
<issue_to_address>
**suggestion:** Consider normalizing/relaxing format_signature matching to reduce brittleness.

The lookup in `_FORMAT_OPERATOR_HINTS` uses `profile.format_signature` verbatim, so case or representation differences (e.g. `PNG`, `image/png`, `riff/wav`) will prevent matches and skip the boosted priors. If the canonical form isn’t already enforced upstream, consider normalizing `format_signature` before lookup (e.g. lowercasing, stripping MIME prefixes, alias mapping) or clearly documenting the expected canonical format here.

Suggested implementation:

```python
# Format signature -> structure-aware mutation operators that are almost
# certainly useful for that format (see core.mutations.FORMAT_MUTATIONS).
#
# The lookup below expects a *normalized* format signature. Call
# `_normalize_format_signature(profile.format_signature)` before using
# `_FORMAT_OPERATOR_HINTS` to avoid brittleness due to case, MIME-style
# prefixes (e.g. `image/png`), or common aliases (`jpg` vs `jpeg`,
# `riff/wav` vs `riff`, etc.).
def _normalize_format_signature(signature: str) -> str:
    """Normalize a format signature into the canonical key used in
    `_FORMAT_OPERATOR_HINTS`.

    This is intentionally conservative; it lowercases, strips common
    MIME-style prefixes, and applies a small alias map for widely-used
    variants. If a format is not recognized, the original (lowercased)
    signature is returned, so adding new formats remains straightforward.
    """
    sig = signature.strip().lower()
    if not sig:
        return sig

    # Common alias mappings for well-known formats.
    alias_map = {
        # PNG
        "png": "png",
        "image/png": "png",

        # JPEG
        "jpeg": "jpeg",
        "jpg": "jpeg",
        "image/jpeg": "jpeg",

        # RIFF container (e.g. WAV)
        "riff": "riff",
        "riff/wav": "riff",
        "wav": "riff",

        # Compression formats
        "gzip": "gzip",
        "application/gzip": "gzip",
        "bz2": "bz2",
        "bzip2": "bz2",
        "xz": "xz",
        "application/x-xz": "xz",
        "zlib": "zlib",
    }

    # Direct alias match first.
    if sig in alias_map:
        return alias_map[sig]

    # For MIME-like strings, prefer the subtype as the canonical key.
    if "/" in sig:
        main, subtype = sig.split("/", 1)
        subtype = subtype.strip().lower()
        if subtype in alias_map:
            return alias_map[subtype]
        # Fall back to subtype if we don't know it explicitly.
        return subtype

    return sig

_FORMAT_OPERATOR_HINTS: dict[str, tuple[str, ...]] = {
    "png": ("png_chunk_mutate", "png_crc_fix"),
    "jpeg": ("jpeg_chunk_mutate", "jpeg_crc_fix"),
    "gzip": ("gzip_chunk_mutate",),
    "bz2": ("gzip_chunk_mutate",),
    "xz": ("gzip_chunk_mutate",),
    "zlib": ("zlib_chunk_mutate",),
}

```

1. Wherever `_FORMAT_OPERATOR_HINTS` is consulted (likely something like `_FORMAT_OPERATOR_HINTS.get(profile.format_signature, ...)`), update the lookup to normalize first, e.g.:
   - Replace `profile.format_signature` with `_normalize_format_signature(profile.format_signature)` in the key used for `_FORMAT_OPERATOR_HINTS`.
2. If the profiler or `Profile` type has documentation/comments about `format_signature`, update them to mention that signatures are normalized via `_normalize_format_signature` and give examples of accepted forms (`PNG`, `image/png`, `riff/wav`, `jpg`).
</issue_to_address>

### Comment 2
<location path="src/fuzzer_tool/core/montecarlo.py" line_range="93-102" />
<code_context>
+    def init_arm(self, name: str, prior_alpha: float = 1.0, prior_beta: float = 1.0) -> None:
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Clarify the documented contract for prior parameters vs. the clamping behavior.

The docstring states prior_alpha/prior_beta "must be > 0", but the implementation clamps them with max(prior_*, MIN_BETA_PARAM). This lets callers pass 0 or negative values that are silently coerced to MIN_BETA_PARAM. Please either document this clamping behavior explicitly or consider raising/logging on non-positive inputs to surface configuration errors earlier.

Suggested implementation:

```python
    def init_arm(self, name: str, prior_alpha: float = 1.0, prior_beta: float = 1.0) -> None:
        """Register a mutation operator arm with a Beta prior.

        Defaults to the uninformative Beta(1, 1) prior. Callers with prior
        knowledge about an operator's likely usefulness (e.g. static target
        profiling indicating a specific file format) can pass a stronger
        prior to bias early Thompson sampling before any evidence has been
        observed. A no-op if the arm is already registered — the prior only
        applies at first registration and is never overwritten by later
        calls, matching the existing idempotent behavior of this method.

        The `prior_alpha` and `prior_beta` parameters are expected to be
        strictly positive. For robustness, the implementation clamps
        non‑positive values up to the internal minimum Beta parameter
        `MIN_BETA_PARAM` via `max(prior_*, MIN_BETA_PARAM)`. This means that
        passing 0 or negative values will not raise, but will instead behave
        as if `prior_* == MIN_BETA_PARAM`.

```

If elsewhere in this docstring (or in parameter docs not shown in the snippet) you explicitly state that `prior_alpha` and `prior_beta` "must be > 0" without mentioning clamping, update that text to reference the clamping behavior described here to keep the contract consistent.
</issue_to_address>

### Comment 3
<location path="tests/test_target_profiler.py" line_range="194-203" />
<code_context>
+class TestFormatOperatorPriors:
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that `interesting_strings` alone also boost dictionary-aware operators

You currently test `magic_bytes` and `boundary_markers` boosting `_DICT_OPERATORS`, but not `interesting_strings`, which is also part of the condition. Please add a test like:

```python
def test_interesting_strings_boost_dict_operators(self):
    p = TargetProfile()
    p.interesting_strings = [b"token"]
    priors = format_operator_priors(p)
    assert "dict_insert" in priors
    assert "dict_append" in priors
```

to exercise the `interesting_strings` branch of `if profile.magic_bytes or profile.boundary_markers or profile.interesting_strings:`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +619 to +626
_FORMAT_OPERATOR_HINTS: dict[str, tuple[str, ...]] = {
"png": ("png_chunk_mutate", "png_crc_fix"),
"jpeg": ("jpeg_chunk_mutate", "jpeg_crc_fix"),
"gzip": ("gzip_chunk_mutate",),
"bz2": ("gzip_chunk_mutate",),
"xz": ("gzip_chunk_mutate",),
"zlib": ("zlib_chunk_mutate",),
"riff": ("bmp_chunk_mutate",),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider normalizing/relaxing format_signature matching to reduce brittleness.

The lookup in _FORMAT_OPERATOR_HINTS uses profile.format_signature verbatim, so case or representation differences (e.g. PNG, image/png, riff/wav) will prevent matches and skip the boosted priors. If the canonical form isn’t already enforced upstream, consider normalizing format_signature before lookup (e.g. lowercasing, stripping MIME prefixes, alias mapping) or clearly documenting the expected canonical format here.

Suggested implementation:

# Format signature -> structure-aware mutation operators that are almost
# certainly useful for that format (see core.mutations.FORMAT_MUTATIONS).
#
# The lookup below expects a *normalized* format signature. Call
# `_normalize_format_signature(profile.format_signature)` before using
# `_FORMAT_OPERATOR_HINTS` to avoid brittleness due to case, MIME-style
# prefixes (e.g. `image/png`), or common aliases (`jpg` vs `jpeg`,
# `riff/wav` vs `riff`, etc.).
def _normalize_format_signature(signature: str) -> str:
    """Normalize a format signature into the canonical key used in
    `_FORMAT_OPERATOR_HINTS`.

    This is intentionally conservative; it lowercases, strips common
    MIME-style prefixes, and applies a small alias map for widely-used
    variants. If a format is not recognized, the original (lowercased)
    signature is returned, so adding new formats remains straightforward.
    """
    sig = signature.strip().lower()
    if not sig:
        return sig

    # Common alias mappings for well-known formats.
    alias_map = {
        # PNG
        "png": "png",
        "image/png": "png",

        # JPEG
        "jpeg": "jpeg",
        "jpg": "jpeg",
        "image/jpeg": "jpeg",

        # RIFF container (e.g. WAV)
        "riff": "riff",
        "riff/wav": "riff",
        "wav": "riff",

        # Compression formats
        "gzip": "gzip",
        "application/gzip": "gzip",
        "bz2": "bz2",
        "bzip2": "bz2",
        "xz": "xz",
        "application/x-xz": "xz",
        "zlib": "zlib",
    }

    # Direct alias match first.
    if sig in alias_map:
        return alias_map[sig]

    # For MIME-like strings, prefer the subtype as the canonical key.
    if "/" in sig:
        main, subtype = sig.split("/", 1)
        subtype = subtype.strip().lower()
        if subtype in alias_map:
            return alias_map[subtype]
        # Fall back to subtype if we don't know it explicitly.
        return subtype

    return sig

_FORMAT_OPERATOR_HINTS: dict[str, tuple[str, ...]] = {
    "png": ("png_chunk_mutate", "png_crc_fix"),
    "jpeg": ("jpeg_chunk_mutate", "jpeg_crc_fix"),
    "gzip": ("gzip_chunk_mutate",),
    "bz2": ("gzip_chunk_mutate",),
    "xz": ("gzip_chunk_mutate",),
    "zlib": ("zlib_chunk_mutate",),
}
  1. Wherever _FORMAT_OPERATOR_HINTS is consulted (likely something like _FORMAT_OPERATOR_HINTS.get(profile.format_signature, ...)), update the lookup to normalize first, e.g.:
    • Replace profile.format_signature with _normalize_format_signature(profile.format_signature) in the key used for _FORMAT_OPERATOR_HINTS.
  2. If the profiler or Profile type has documentation/comments about format_signature, update them to mention that signatures are normalized via _normalize_format_signature and give examples of accepted forms (PNG, image/png, riff/wav, jpg).

Comment on lines +93 to +102
def init_arm(self, name: str, prior_alpha: float = 1.0, prior_beta: float = 1.0) -> None:
"""Register a mutation operator arm with a Beta prior.

Defaults to the uninformative Beta(1, 1) prior. Callers with prior
knowledge about an operator's likely usefulness (e.g. static target
profiling indicating a specific file format) can pass a stronger
prior to bias early Thompson sampling before any evidence has been
observed. A no-op if the arm is already registered — the prior only
applies at first registration and is never overwritten by later
calls, matching the existing idempotent behavior of this method.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Clarify the documented contract for prior parameters vs. the clamping behavior.

The docstring states prior_alpha/prior_beta "must be > 0", but the implementation clamps them with max(prior_*, MIN_BETA_PARAM). This lets callers pass 0 or negative values that are silently coerced to MIN_BETA_PARAM. Please either document this clamping behavior explicitly or consider raising/logging on non-positive inputs to surface configuration errors earlier.

Suggested implementation:

    def init_arm(self, name: str, prior_alpha: float = 1.0, prior_beta: float = 1.0) -> None:
        """Register a mutation operator arm with a Beta prior.

        Defaults to the uninformative Beta(1, 1) prior. Callers with prior
        knowledge about an operator's likely usefulness (e.g. static target
        profiling indicating a specific file format) can pass a stronger
        prior to bias early Thompson sampling before any evidence has been
        observed. A no-op if the arm is already registeredthe prior only
        applies at first registration and is never overwritten by later
        calls, matching the existing idempotent behavior of this method.

        The `prior_alpha` and `prior_beta` parameters are expected to be
        strictly positive. For robustness, the implementation clamps
        nonpositive values up to the internal minimum Beta parameter
        `MIN_BETA_PARAM` via `max(prior_*, MIN_BETA_PARAM)`. This means that
        passing 0 or negative values will not raise, but will instead behave
        as if `prior_* == MIN_BETA_PARAM`.

If elsewhere in this docstring (or in parameter docs not shown in the snippet) you explicitly state that prior_alpha and prior_beta "must be > 0" without mentioning clamping, update that text to reference the clamping behavior described here to keep the contract consistent.

Comment on lines +194 to +203
class TestFormatOperatorPriors:
def test_no_hints_when_profile_empty(self):
p = TargetProfile()
assert format_operator_priors(p) == {}

def test_png_format_boosts_png_operators(self):
p = TargetProfile()
p.format_signature = "png"
priors = format_operator_priors(p)
assert priors["png_chunk_mutate"] == (2.0, 1.0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add a test that interesting_strings alone also boost dictionary-aware operators

You currently test magic_bytes and boundary_markers boosting _DICT_OPERATORS, but not interesting_strings, which is also part of the condition. Please add a test like:

def test_interesting_strings_boost_dict_operators(self):
    p = TargetProfile()
    p.interesting_strings = [b"token"]
    priors = format_operator_priors(p)
    assert "dict_insert" in priors
    assert "dict_append" in priors

to exercise the interesting_strings branch of if profile.magic_bytes or profile.boundary_markers or profile.interesting_strings:.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR seeds the Thompson-sampling operator scheduler (MonteCarloScheduler) with informative Beta priors derived from static target profiling, so operator selection can start biased toward format- and token-relevant mutations instead of always starting from Beta(1, 1).

Changes:

  • Added format_operator_priors() to derive per-operator (alpha, beta) overrides from TargetProfile format/token hints.
  • Extended MonteCarloScheduler.init_arm() to accept optional Beta prior parameters (with clamping) and exposed a supports_priors capability flag.
  • Wired the fuzzer’s arm registration to pass priors only to schedulers that advertise prior support; updated README and added unit tests.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_target_profiler.py Adds unit tests for format_operator_priors() output and basic prior sanity checks.
tests/test_montecarlo.py Adds unit tests verifying informative priors, idempotency, and clamping behavior in init_arm().
src/fuzzer_tool/services/fuzzer.py Passes derived operator priors into arm registration for schedulers that support priors (MC bandit).
src/fuzzer_tool/core/target_profiler.py Introduces operator-prior derivation and format/operator hint tables used to seed the bandit.
src/fuzzer_tool/core/montecarlo.py Updates the Thompson scheduler to accept per-arm Beta priors and clamps invalid parameters.
README.md Documents the new informative-prior behavior under static target analysis.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +619 to +627
_FORMAT_OPERATOR_HINTS: dict[str, tuple[str, ...]] = {
"png": ("png_chunk_mutate", "png_crc_fix"),
"jpeg": ("jpeg_chunk_mutate", "jpeg_crc_fix"),
"gzip": ("gzip_chunk_mutate",),
"bz2": ("gzip_chunk_mutate",),
"xz": ("gzip_chunk_mutate",),
"zlib": ("zlib_chunk_mutate",),
"riff": ("bmp_chunk_mutate",),
}
Comment on lines +640 to +643
# Beta prior for operators the profile suggests are relevant: same total
# "pseudo-observation" mass as the uninformative default (1, 1), but shifted
# toward success so Thompson sampling favors them before real evidence
# arrives. Weak enough that a handful of real failures will correct it.
daedalus added a commit that referenced this pull request Jul 16, 2026
Seed Thompson-sampling bandit with informative priors from static target profiling
daedalus added a commit that referenced this pull request Aug 2, 2026
The x86 instruction-stream decoder (_decode_insns) was the #1 CPU
consumer (0.216s/1000 iters) on targets where x86 mutations are
irrelevant (PNG fuzzing): gating the operator behind a CLI flag cuts
throughput cost to a single _AVAILABLE predicate check. Follows the
enable_regex_bomb template: argparse flag + Fuzzer kwarg + registry
availability predicate; no changes to build_dispatch/build_ops/
_register_arms. Removes the arm hint from _FORMAT_OPERATOR_HINTS so the
profiler no longer auto-suggests it. Throughput 526 -> 664 eps (+26%)
on the 2000-iter PNG hotpath run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants