heretic/tests
red40maxxer c8a254b825
Some checks failed
CI / Check and build (Python 3.10) (push) Has been cancelled
CI / Check and build (Python 3.11) (push) Has been cancelled
CI / Check and build (Python 3.12) (push) Has been cancelled
CI / Check and build (Python 3.13) (push) Has been cancelled
feat: generic plugin system (#53)
* style: ruff

* feat(wip): populate metadata fields and allow plugins to declare what they need

* refactor: extract metadata logic to separate module

* style: placate ruff

* chore: use eos token for inferring finish reason with fallback

* fix: handle empty responses better

* style: ruff

* refactor: combine response text and metadata into single object

* refactor: clean up tagger and scorer usage

* style: ruff

* chore: remove is_refusal

* style: ruff import ordering

* feat: remove embeddings and generation traces

* feat: return all hidden states instead of just last ones

* chore: remove testing changes

* style: ruff format

* fix: mismatching stop reason identifier

* chore: update default config ordering

* chore: fix merge

* feat: allow external plugin imports

* feat: add good_residuals and bad_residuals to context metadata

* style: ruff

* chore: remove unnecessary allow extra

* chore: remove unnecessary system prompt and model name

* style: ruff

* perf: clear residuals from memory if plugin doesn't need them

* feat: support external filepaths and clean up import logic

* style: ruff

* refactor: consolidate tagger and scorer functionality into a single scorer plugin

* refactor: parent Plugin class for all plugins

* feat: support multiple scorer plugins

* refactor: type fixes

* style: satisfy ruff

* refactor: centralize scorer dataclasses

* refactor: rename MetricResult to Score

* feat: simplify plugin loading

* feat: split response metadata objects and access in evaluationContext

* style: ruff

* style: ruff

* chore: remove old tagger code

* refactor: scorer settings inherit directly from Pydantic

* refactor: move eval prompts and settings to CountRefusals and KLDivergence

* feat: move scorer config to top level and add support for scale factor

* fix: missing config for scorers

* style: ruff

* fix: scale type error

* docs: fix misleading docstring

* fix: clean up old fields

* refactor: use BaseModel for scorer settings

* chore: make scale default to 1 for safety

* refactor: get metadata dynamically through EvaluationContext

* refactor: rename CountRefusals to RefusalRate

* chore: remove unused kl_divergence config fields

* docs: restore missing comment

* refactor: remove unused code

* chore: specify settings and model field types

* refactor: rename to prompts

* refactor: move load_plugin to plugin

* style: ruff

* refactor: update optimization direction config to use StudyDirection directly

* fix: missing TypeVar

* fix: missing imports

* fix: use OptimizationDirection peoperly

* chore: remove names

* chore: remove unecessary future import

* chore: remove unused scorer imports

* refactor: objective should only return tuple of floats

* refactor: use dataclass for scorer config

* feat: support multiple instances of the same scorer

* style: ruff

* fix: nonexistent name attribute in scorer

* refactor: clear residuals and analyser

* docs: MetricResult -> Score

* fix: clean up default toml

* fix: missed renaming to RefusalRate

* chore: missing return ModuleType

* docs: add SPDX header

* docs: add SPDX header

* docs: add SPDX header

* chore: fix misleading field description leftover from old code

* chore: add newline

* chore: unused settings class

* fix: bad import

* refactor: rename ResponseText -> TextCompletion

* feat: simplify api

* refactor: rename to get_score

* feat: namespace scorer configs

* style: ruff

* fix: genericize readme intro

* chore: move init to scorer base class

* refactor: handle direction and scale outside scorer

* chore: use underscore for instance names

* fix: add scorer instance name to scores

* refactor: create structured api for scorers to access model

* refactor: rename plugin-specific Settings to PluginSettings

* feat: add instance name to plugin load logging

* style: ruff

* chore: allow extra fields for plugins

* fix: improve plugin loading logic

* chore: undo change fixed in master

* chore: remove old code

* docs: adjust docstring

* chore: cleanup import

* refactor: unnest plugin settings class and detect from type annotation

* refactor: use plain str instead of Response object with metadata

* refactor: move non evaluator-specific methods out

* refactor: use enum for StudyDirection

* refactor: no strings as type annotations

* chore: let evaluator blow up on error

* refactor: rename metrics to scores globally

* feat: separate cli and hf score displays and clean up readme logic

* fix: direction serialization ValidationError when restoring from save

* refactor: rename scorer start() to setup()

* style: ruff

* fix: remove external plugin test

* refactor: rename setup to init

* docs: formatting

* refactor: move scorers location in config

* docs: add comment describing return tensor shape

* style: ruff

* refactor: simplify scorer setting logic

* refactor: clarify plugin loading logic

* refactor: remove unnecessary hashing and inline import_module

* style: ruff

* fix: don't use classnames for readme

* refactor: don't expose heretic settings to scorer

* fix: adjust print responses logic and move to scorer config level

* refactor: separate baseline score computation

* refactor: rename hf_display to md_display

* style: ruff

* Update src/heretic/scorer.py

Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>

* Update src/heretic/scorer.py

Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>

* style: ruff

* fix: ty error

* refactor: bind Score names to parent Scorers as class property

* docs: fix doc

* docs: update comment

* style: remove changes

* chore: define default refusal markers

* style: ruff

* style: remove whitespace changes

* docs: tweak docs

* chore: cleanup from merge

* style: ruff

* fix: handle negative floating point kld

* style: formatting

* chore: remove unused code

* chore: ruff

* style: undo line removal

* style: update formatting and remove old comment

* docs: undo style change

* docs: update field description

* docs: tweak docstring

* chore: revert kld absolute value forcing

* style: ruff

* chore: cleanup

* docs: update header

* docs: update header

* refactor: remove unnecessary conditional imports

* fix: apply review omments on refusalrate

* refactor: move contract validation to plugin

* refactor: move Context to Plugin

* refactor: move init to plugin level

* refactor: move init() to plugin

* style: ruff

* docs: update SPDX header

* refactor: derive score name from scorer.score_name

* chore: no None option for baseline_score_displays

* fix: show CLI formatted metrics in trial selection

* fix: sort trials by scores

* chore: remove unnecessary from future import

* chore: remove scorer scale field

* refactor: import Context from plugin

* docs: add quote to direction

* refactor: move model_config to the end of the class

* refactor: use dataclass for consistency

* refactor: use BaseModel and store study direction as str

* docs: move docstring location

* refactor: combine scorer load and init

* refactor: use best_trials for single and multi-objective

* refactor: remove all .get()

* refactor: remove unused dataclass

* refactor: use ScorerEntry dataclass for improved code quality

* style: ruff

* chore: adapt reproducibility to plugin architecture

* chore: address PR comments

* chore: make `ScorerConfig` fields full `Field()`

* chore: address pr comments

* feat: bump to version 3 of reproduce json

* refactor: rename direction to optimization

* refactor: rename loop var

* feat: pin to dataset commit sha for reproducibility

* style: ruff

* feat: show metric as list instead of table

* chore: remove stale comment

* chore: resync with upstream

* fix: trial title formatting

* chore: single source of truth for optimization objective ordering

* feat: fail-fast when there are no optimization objectives

* chore: remove dead `verify_hashes`

* refactor: pair scores with baselines everywhere

* fix: bug

* chore: add recommendation to install heretic 1.4 for older reproduce files

* chore: adapt nohumor and noslop config files to new format

* refactor: rename refusals to residuals everywhere

* fix: merge issues

* fix: fix test configs

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* style: ruff

* chore: validate `instance_name` early

* chore: add return type for `load_prompts`

* docs: comment typo

* docs: comments

* docs: comments

* chore: comments and spacing

* docs: comments

* Update src/heretic/evaluator.py

Co-authored-by: Vinay Umrethe <umrethevinay@gmail.com>

* refactor: rename `cli_display` to `rich_display`

* style: ruff

* fix: don't repro external plugins or local datasets

* test: adapt minicpm5 to scorer-based format

* test: adapt qwen2.5 to scorer based format

* chore: restore comment

* chore: address pr comments

* chore: remove stale `keyword_markers`

* chore: string

* style: ruff

* refactor: make KLD and keyword rate scorers default

---------

Co-authored-by: mad-cat-lon <113548315+mad-cat-lon@users.noreply.github.com>
Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Vinay Umrethe <umrethevinay@gmail.com>
2026-07-07 14:34:33 +05:30
..
gemma-4e feat: generic plugin system (#53) 2026-07-07 14:34:33 +05:30
minicpm5 feat: generic plugin system (#53) 2026-07-07 14:34:33 +05:30
mistral-3 feat: generic plugin system (#53) 2026-07-07 14:34:33 +05:30
qwen2.5 feat: generic plugin system (#53) 2026-07-07 14:34:33 +05:30
qwen3.5-moe feat: generic plugin system (#53) 2026-07-07 14:34:33 +05:30
README.md fix: use W_org matrix only where needed (#398) 2026-07-01 16:13:14 +05:30
run_tests.py feat: headless operation + end-to-end tests (#392) 2026-06-27 13:41:48 +05:30

Test Suite Guide

Whenever we change any code-logic related to src/heretic/model.py or config.toml (e.g. row_normalization, full_normalization_lora_rank, winsorization_quantile, etc) which can affect a model's reproduciblity; Use these tests which are designed to verify that those changes does not affect reproducibility, unless they are meant to (like when we'll integrate ARA branch in future).

How to test

  1. Choose any model from tiny-random org which provides tiny models useful for debugging.

Example: tiny-random/minicpm5.

Note

It is highly recommended to use a model which does not have a special_tokens_map.json file in the repo. Because those files are almost always wrong in tiny-random/* models compared to the original model.

  1. Clone that model repository using Git and generate the SHA256 hashes using sha256sum:

On Linux:

sha256sum -b * > ../SHA256SUMS.LABEL

On Windows:

sha256sum * | Out-File -Encoding utf8NoBOM ../SHA256SUMS.LABEL

Tip

On windows, sha256sum is generally pre-installed by Git for windows.

Verify with:

Get-Command sha256sum`

Expected:

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     sha256sum.exe                                      0.0.0.0    C:\Program Files\Git\usr\bin\sha256sum...

Note

You must use Windows Powershell v7.X not the core which is v5.1. This is required for -Encoding utf8NoBOM to work.

See Differences between Windows PowerShell 5.1 and PowerShell 7.x documentation.

Where LABEL describes the type of system you are running the tests on.

Example:

  • SHA256SUMS.windows (For windows)
  • SHA256SUMS.ci (For GitHub CI)
  • SHA256SUMS.linux (For linux)
  1. Run the tests with:
uv run run_tests.py

The output hashes should FAIL against the Valid hashes in SHA256SUMS file of the test model you added. This is expected since Heretic changes the model. Without Step 2, the test model's folder will simply be ignored because it will not have a hash SUMS file to compare against.

  1. After that go to the output TEST_MODEL_DIR/model folder and re-generate the Actual hashes based on the system you are using.
cd TEST_MODEL_DIR/model
sha256sum -b * > ../SHA256SUMS.LABEL # or use windows command.
  1. Re-run the tests with:
uv run run_tests.py

This time the tests should PASS because we added the new hashes which are expected to be reproduced on the same system.

  1. After that push the SHA256SUMS.LABEL files and wait for GitHub CI actions to run those tests.

Since PyTorch does not guarantee exact cross-system reproducibility regardless of configuration, multiple valid hashes can be provided for each output file. The above update must be performed for each TEST_MODEL_DIR and on each type of system.

For this, copy the Actual hash value for each mismatched unidentical file into a SHA256SUMS.ci file.

  1. After that push the SHA256SUMS.ci files and wait for GitHub CI actions to re-run those tests.

This time the tests should PASS because we added the new hashes which are expected to be reproduced on CI.