Skip to content

Version 2 - #22

Merged
aakankschit merged 32 commits into
mainfrom
streamline/v2
Sep 10, 2026
Merged

aakankschit merged 32 commits into
mainfrom
streamline/v2

Conversation

@aakankschit

Copy link
Copy Markdown
Owner

Version 2 streamlines the code base further and removes the legacy methods. Updates the documentation and makes it easier for the user to use the package.

Aakankschit Nandkeolyar and others added 30 commits September 8, 2026 22:13
- Remove tracked sampler.py.backup and reagent.py.backup
- Remove .gitattributes LFS rule: data/ is gitignored so the rule
  matched zero tracked files (git lfs ls-files was empty)
- Drop the matching no-op lfs: true / git lfs pull steps from the
  test and publish workflows

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
The legacy tree (17 modules, 1.2 MB) had no importers in src/ or tests/
and shipped in every wheel. The Zhao 2025 RWS reproduction remains
available at tag v.1.2.0.

BREAKING CHANGE: TACTICS.thompson_sampling.legacy no longer exists.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
baseline.py could not execute: it read config.evaluator_class_name,
evaluator_arg, reaction_smarts and reagent_file_list, none of which
exist on RandomBaselineConfig, and called create_reagents(ts_mode=...)
with a keyword that signature never accepted. run_random_baseline and
run_exhaustive_baseline were exported but had no callers anywhere.

BREAKING CHANGE: RandomBaselineConfig, run_random_baseline and
run_exhaustive_baseline are removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
- evaluators.py: drop test_fred_eval / test_rocs_eval /
  test_ml_classifier_eval stubs and the __main__ block (never
  collected by pytest; constructed real OpenEye objects)
- top_two_selection.py: drop unreferenced disagreement_rate and
  component_disagreement_rates properties
- reagent.py: drop compatible_smarts property, add_compatible_smarts,
  is_compatible_with (zero callers; set_compatible_smarts stays)
- disallow_tracker.py: drop unused sample() and the random import
- ts_utils.read_reagents: drop the smarts_compatibility parameter
  that no caller ever passed (the sampler applies compatibility via
  SynthesisPipeline.auto_detect_compatibility instead)
- config.py: drop unused model_validator, Literal, logging imports

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
- Delete conformer_gen.py: never imported anywhere, and its unguarded
  module-top openeye import made it unimportable without the optional
  [openeye] extra
- generate_products.py: drop generate_combinations_parallel (no
  callers) and the deprecated LibraryEnumerator class
- enumeration_utils.py: drop read_all_reagent_files, smiles_to_mol,
  and find_reactants_from_product_code (no callers; the last was also
  broken -- a nested closure passed to a spawn-context Pool)
- constants.py: drop derived SALT_FRAGMENT_SMILES (never consumed)
- _validator.py: drop unused rdkit.Chem.Draw import
- Trim now-unused typing/polars/os imports

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
- Delete library_analysis.py (LibraryAnalysis) and
  library_analysis_utils.py: their only consumer was the dead
  LibraryVisualization class or a gitignored notebook
- visualization.py: delete LibraryVisualization (371 lines, sole user
  of seaborn/matplotlib/pandas/IPython in this module) and
  get_performance_summary; the module is now polars + altair only
- diagnostic_plots.py: delete eight plot functions with no callers
  (disagreement/scale/TT-TS-decomposition trajectories, posterior
  heatmap, convergence comparison, min-GMIC-vs-advantage, oracle
  flexibility, GMIC-vs-oracle) and the unused _rolling_mean helper.
  The eight functions used by tutorials are unchanged.
- library_analysis/__init__.py exports TS_Benchmarks only

BREAKING CHANGE: TACTICS.library_analysis.LibraryAnalysis,
LibraryVisualization, compile_product_scores and
compile_product_smiles are removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
useful_rdkit_utils cost 3.85 s of the 7.1 s import (it pulls umap ->
pynndescent -> numba -> llvmlite, ~149 MB) to supply MolWt and two
Morgan-fingerprint wrappers. Replace with rdkit.Chem.Descriptors.MolWt
and a shared rdFingerprintGenerator Morgan generator (radius 2, 2048
bits) -- verified bit-identical, and it drops the deprecation warning
uru's smi2morgan_fp emitted.

pandas was used only to read the LookupEvaluator table and the
validator's CSV reagent files; both now use Polars (null score cells
map to NaN so the sampler's NaN-skip path is unchanged).

dill was imported solely by multiprocessing_utils.initializer, which
set dill.settings -- a value the stdlib Pool never consults. Delete the
module and the initializer= kwarg; the pool already pickled plain
dicts and SMILES strings.

seaborn's single call site was deleted with LibraryVisualization.

import TACTICS: 7.1 s -> 1.0 s.

BREAKING CHANGE: TACTICS.library_enumeration.initializer is removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
product_scores.csv (12.1 MB, 94% of the uncompressed wheel) becomes
product_scores.parquet (4.7 MB, zstd). Same 499,720 rows and schema
(Product_Code: str, Scores: f64); round-trip verified equal.
LookupEvaluator already dispatched on the .parquet extension.

BREAKING CHANGE: the bundled dataset path is now
TACTICS/data/thrombin/product_scores.parquet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
…nches

Config fields that were plumbed end-to-end (Pydantic field -> factory
kwarg -> __init__ assignment) but never read by any code path:
- RouletteWheelConfig: exploration_phase_end, transition_phase_end,
  min_observations, cats_exploration_fraction (+ their validator)
- BayesUCBConfig: exploration_phase_end, transition_phase_end (+ validator);
  its min_observations and cats_exploration_fraction ARE live and stay
- TopTwoConfig: min_observations (self-documented as inert)

ThompsonSamplingConfig.max_resamples: the early-stop branch in
search() compared against a counter that was reset every iteration and
never incremented, so the field had no effect. Removed from config,
sampler, presets and docstrings.

Sampler diagnostics: the 3-column (cycle, component_idx, criticality)
fallback was reachable by no shipped strategy -- every strategy that
implements get_component_criticality also implements
get_component_state. The empty frame now uses the three columns all
enhanced schemas share (current_cycle, component_idx, criticality) and
diagnostics.compute_convergence_point no longer sniffs for a 'cycle'
column.

Strategy and warmup config models now reject unknown fields
(extra='forbid') so scripts passing removed knobs fail loudly.

BREAKING CHANGE: the fields above are removed; passing them raises
ValidationError.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
The preset existed to reproduce Zhao et al. (2025); that reproduction
is pinned at chem-tactics 1.2.0. The Boltzmann-weighted posterior
update it used is unchanged -- it remains the update rule for the
recommended and recommended_rws presets.

BREAKING CHANGE: get_preset('legacy_rws') raises ValueError.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
…ncedWarmup

StandardWarmup (random partners with replacement) was the baseline
comparison arm and consistently the weakest warmup. Remove it and its
config model.

ThompsonSampler(...) constructed directly with no warmup_strategy now
defaults to EnhancedWarmup(), matching what from_config() and every
preset already did. The unreachable 'else StandardWarmup()' branch in
from_config is gone (config.model_post_init guarantees warmup_config).

Three tests skipped as 'Warmup has edge case with small test data'
pass with the Enhanced default and are un-skipped. Three others still
fail, in search() rather than warmup (an all-NaN slice on a tiny
library, and a None evaluator in a pool worker with
product_library_file); their skip reasons are updated to say so.

BREAKING CHANGE: StandardWarmup and StandardWarmupConfig are removed;
the direct-construction default warmup changes from Standard to
Enhanced.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
RouletteWheelSelection, TopTwoSelection and BayesUCBSelection each
carried their own copies of the heated-component index, round-robin
rotation, flexibility-weighted rotation, and (for the first two) the
GMIC computation. The two GMIC bodies had already drifted -- one wrapped
its result in float(), the other did not -- and a 2026-06 comment in
TopTwo explained its gate removal as 'for consistency with
RouletteWheelSelection', which is the tell that this should be one
implementation.

New private module strategies/_thermal.py:
- ThermalCyclingMixin: current_component_idx, rotate_component,
  rotate_component_weighted (template method; exactly one rng.choice
  after deterministic weights), _rotation_flexibility hook
- GMICCriticalityMixin(ThermalCyclingMixin): _calculate_gmic_details,
  _calculate_gmic, get_component_criticality, GMIC-weighted
  _rotation_flexibility with the shared _cached_gmics cache

RWS and TT-TS inherit GMICCriticalityMixin; BayesUCB inherits
ThermalCyclingMixin and supplies its criticality-weighted hook. TT-TS's
_component_gmic is renamed to _cached_gmics. RWS's write-only
_mean_criticality is dropped (BayesUCB keeps its own, which is read).

Also deleted: RWS.select_batch (60 lines duplicating select_reagent;
never called by the sampler -- callers fall through to the base default)
and BayesUCB.select_batch (byte-equivalent to the base default).

adapt_temperatures and reset_temperature stay per-class: their
zero-unique branches genuinely differ in direction, and merging them
would hide that; cross-reference comments added instead.

Verified RNG-identical: seeded 30-cycle thrombin runs for all three
strategies hash identically before and after (selected compound
sequence + heated-component sequence).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Before: import TACTICS took 7.1 s, and even a pure config import paid
~6 s, because config.py -> core.evaluator_config tripped
core/__init__.py, which eagerly imported the sampler, every evaluator,
and their dependencies (RDKit, sqlitedict, and -- via strategies --
scipy.stats).

New TACTICS._lazy.install() gives a package a PEP 562 __getattr__ over
a {name: submodule} map; the four hubs (TACTICS, .thompson_sampling,
.thompson_sampling.core, .library_analysis) now resolve names on first
access. Every existing import path keeps working: top-level
(from TACTICS import ThompsonSampler), hub (from
TACTICS.thompson_sampling import TopTwoSelection) and full submodule
paths. TYPE_CHECKING blocks keep IDEs/pyright informed. Spawned
multiprocessing workers resolve classes by module path, so parallel
evaluation is unaffected.

Leaf deps deferred to the call that needs them: scipy.stats in
BayesUCBSelection._compute_ucb_indices; matplotlib.pyplot via a
_pyplot() helper in diagnostic_plots (also replaces plt.cm.get_cmap,
removed in matplotlib 3.9, with matplotlib.colormaps). altair's import
in visualization.py is guarded with an install hint.

pyproject: matplotlib and altair move from dependencies to a new [viz]
extra; [tutorials] includes them. Core dependencies are now pydantic,
rdkit, numpy, scipy, polars, tqdm, sqlitedict, joblib.

tests/test_import_time.py pins the contract in fresh subprocesses.

import TACTICS: 7.1 s -> 0.04 s. Config import: ~6 s -> 0.14 s.

BREAKING CHANGE: plotting now requires pip install chem-tactics[viz].

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
- pyproject: version 2.0.0
- CHANGELOG: full Removed / Changed / Performance / Fixed entry
- README: drop legacy_rws row; document the [viz] extra
- docs: library_analysis.rst rewritten around what exists
  (TS_Benchmarks + the eight real diagnostic_plots functions -- the old
  page documented five plot functions that never existed);
  StandardWarmup anchors, legacy_rws rows, max_resamples and the inert
  phase_end fields removed from configuration/thompson_sampling/
  strategies.rst; conf.py autodoc mocks trimmed. Sphinx builds with no
  warnings.
- tutorials: StandardWarmupConfig -> EnhancedWarmupConfig; drop
  max_resamples kwargs; interactive_sar_explorer uses Polars; remove
  the BoltzmannConfig UI from thompson_sampling_tutorial (that class
  never existed, so the notebook could not be opened). All three pass
  marimo check.
- delete src/TACTICS/README.md: a stale duplicate front page describing
  a Boltzmann strategy, Stratified/Latin-Hypercube warmups and a
  run_ts() in main.py, none of which exist; not packaged, not linked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
conf.py
- Import the installed package instead of a sys.path hack that pointed
  at the repo root (the package lives in src/ and was never importable)
- version/release from importlib.metadata (were hardcoded '0.0')
- autodoc_mock_imports = [] -- the real package is installed and mocks
  at sys.meta_path[0] would shadow it and break Pydantic model import
- MyST dollarmath + amsmath, heading anchors to depth 4, ready for the
  theory pages
- GitHub/PyPI icon links; html_context + use_edit_page_button so the
  'edit this page' item actually renders
- Fresh polars intersphinx URL; linkcheck settings
- Two hooks for Pydantic models under autodoc: render a Fields block
  from model_fields (descriptions and defaults read from the code) and
  hide model_*, validators and the generated __init__. Dormant until
  reference pages land.

pyproject [docs]: version floors (sphinx>=8,<9; sphinx-design>=0.6.1
for Sphinx 8) plus matplotlib/altair so a docs install can import
library_analysis for autodoc.

docs.yml: install -e '.[docs]' instead of a hardcoded list that
duplicated the extra; build with -W --keep-going; checkout@v4 /
setup-python@v5 with pip cache; upload the HTML as an artifact on PRs;
separate non-blocking linkcheck job; run on PRs to streamline/v2.

Makefile: html target mirrors CI flags; clean/linkcheck/livehtml.

custom.css: drop rules with no consumer (badges, migration table,
returns table, graphviz-wide, version badge, depends-on, method
category, class-methods, sd-* overrides pydata already provides).
415 -> 284 lines.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
…s_filename

Docstrings the API reference needs:
- Evaluator ABC: the contract (evaluate(mol) -> float, counter, NaN =
  skip) and how evaluators are built from configs
- each of the 8 evaluator classes: what it scores, its input_dict keys,
  its paired *EvaluatorConfig, speed/licence notes; CustomEvaluator
  states the picklability rule for processes > 1
- ThompsonSampler: full NumPy-style Parameters block (7 of 12 were
  undocumented) and the direct-construction call order

API:
- TACTICS and TACTICS.thompson_sampling lazy hubs now export Evaluator,
  CustomEvaluator and all 16 config models (strategy, warmup, evaluator),
  so docs can show one canonical import style
- RouletteWheelSelection.__init__ drops its **kwargs, which had no
  handler and silently swallowed typos (criticality_metric='shannon'
  was accepted with no effect); BayesUCBSelection keeps its deprecated-
  name warning and raises TypeError for anything else
- Remove ThompsonSamplingConfig.results_filename: from_config never
  passed it and the sampler never wrote it. Preset output_dir now only
  places the log. Remove the unread ThompsonSampler(cats_manager=)
- bayes_ucb docstring default 0.5 -> 0.3 (matches code);
  get_diagnostics '17-column' -> 18

Tutorials: fix stale notebooks/ paths and the manuscript_plots.py
reference in module docstrings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
docs/source/snippets/<block>_<name>.py hold every code example the
guides will show. Each is a runnable script on the bundled thrombin
data with a [start:tag]/[end:tag] region for literalinclude, its code
inside main() (required so processes > 1 snippets survive
multiprocessing's spawn re-import), and smoke assertions outside the
displayed region.

tests/test_doc_snippets.py runs each one in a temp cwd via runpy
(honours '# requires: viz|openeye' headers with importorskip), and
asserts the README quickstart is byte-identical to the [start:search]
region of search_minimal.py -- the two can no longer diverge.

README quickstart now runs as-is on the bundled data (the old one used
placeholder paths). test.yml installs [test,viz] so viz snippets are
not permanently skipped in CI.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
- base_strategy.select_reagent / select_batch: rewrite in Google style
  (the 'Parameters:' header with both a colon and a dash underline was
  not recognised by napoleon, so the raw **kwargs reached docutils as an
  unclosed strong marker; inherited by UCB/EpsilonGreedy too)
- visualization.get_barplot_TS_results_data: proper NumPy section
  headers and the blank line before Returns
- diagnostic_plots.plot_rws_diagnostic: the indented axis description
  parsed as a block quote; make it a list

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
docs/source/reference/{library,scoring,search,scale,inspect,visualise,
extending}.rst -- every public symbol documented exactly once, by full
submodule path (the package hubs are lazy; autodoc on a hub renders
empty). Pydantic configs render a generated Fields block with the
description and default of every field, read from model_fields.

Three conf.py findings on the way:
- autodoc_default_options = {'members': True} silently overwrote every
  explicit ':members: a, b' list (a bool default takes the else branch
  in process_documenter_options). Dropped; directives name members.
- napoleon rendered 'Attributes:' sections as .. attribute:: object
  descriptions, colliding with real @Property members
  (SynthesisPipeline.reagent_file_list). napoleon_use_ivar = True.
- autodoc_class_signature='separated' added __init__/__new__ entries
  that bypass autodoc-skip-member, leaking Pydantic's boilerplate.
  'mixed' puts the signature on the class line; the hook strips the
  boilerplate napoleon merges in.

guides/*.rst and extending.rst are stubs so the reference pages' links
resolve; the guides replace them in the next phases. Root toctree gains
Guides and Reference sections; the 1.x pages stay until superseded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
docs/{thompson_sampling_equations,bayesian_ucb_equations,
search_performance_metrics}.md -> docs/source/theory/, with a theory/
index in the root toctree. MyST dollarmath renders the LaTeX (242
display blocks in the TS document); the six cross-file anchor links
resolve unchanged under MyST's GitHub-compatible slugs.

Structure: hand-maintained tables of contents removed (the sidebar
replaces them); the subtitle H2s become italic lines and the '---'
rules go, since a transition at a section start is a docutils error.

Content that was false about the 2.0 API:
- TS equations §10: max_resamples dropped; seed/processes/
  min_cpds_per_core/product_library_file added; RouletteWheelConfig
  table rebuilt from the live fields (exploration_phase_end,
  transition_phase_end, min_observations, criticality_metric were
  never RWS fields and the example raised ValidationError); a Top-Two
  section added -- the recommended strategy had none; StandardWarmup
  section removed; Enhanced relabelled from 'Legacy' to the default it
  is; tuning table updated
- Bayes-UCB §10: exploration_phase_end/transition_phase_end replaced by
  the real cats_exploration_fraction in the table, effects and all
  three examples (which raised ValidationError)
- §6.6 warmup comparison row reflects 2.0

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
guides/01_library.rst replaces library_enumeration.rst (1,431 lines of
hand-written reference now generated in reference/library). Core:
define the bundled thrombin library, make one product, validate SMARTS
coverage against the real reagent files. Build on it: multi-step
synthesis, alternative SMARTS, protecting groups/salts, enumerate
everything without TS. Three snippets executed by the suite.

read_reagent_file is now exported from TACTICS.library_enumeration --
it is the natural way to read a reagent file and the guide needs it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Core: the lookup table on the bundled data, and the two decisions that
travel with every scorer (direction lives on the strategy; what
'missing' means -> default_score). Build on it: your own Python
function via CustomEvaluatorConfig with the module-level rule for
parallel runs; the table of all eight scorers by cost and requirement;
using an evaluator class directly. Gotchas cover the drift-audit
findings (FPEvaluatorConfig has no radius/bits; evaluator configs are
permissive).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
guides/03_search.rst replaces configuration.rst, thompson_sampling.rst
and strategies.rst (2,753 lines; the reference half is now generated in
reference/search). Core: the five calls, the four parameters that
matter first, what search() returns, and an Imports box explaining the
lazy hubs. Build on it: the three presets with their benchmark numbers,
a hand-built config, how each strategy turns posterior draws into a
pick and how GMIC chooses the heated component, Enhanced vs Balanced
warmup with their actual costs, driving the sampler directly. Gotchas
include the two crashing 1.x examples and the unseeded-warmup caveat.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Core: processes / min_cpds_per_core, how workers rebuild the evaluator
from its config (and why that is the parallel-safe path), when
parallelism pays. Build on it: product_library_file, budgeting a run
(max_evaluations; what warmup costs for an expensive scorer), cluster
notes incl. the __main__ guard for spawn. Snippet runs a real 2-process
search on the fingerprint scorer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Core: track_diagnostics and the three accessors -- get_diagnostics,
get_posterior_landscape, get_sar_summary -- with what each returns.
Build on it: the columns worth watching per strategy (TT-TS 12, RWS
18, Bayes-UCB 18), the six analysis functions, and how to stack runs
for the replicate-averaged plots. Snippet runs a tracked search and
exercises compute_posterior_entropy / compute_convergence_point /
format_sar_report, writing Parquet for the next block.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
guides/06_visualise.rst replaces library_analysis.rst -- the last of the
six 1.x pages. Core: TS_Benchmarks comparing the two recommended presets
against the exhaustive thrombin scores (two seeded replicates each),
with the three chart methods. Build on it: the eight diagnostic plots
grouped by what they need -- single-run, replicate-averaged, layered --
and the phase/replicate/method column contract, which nothing else
documented. Gotchas: no_of_cycles means replicates; reference column
order; sort_type must match mode. Both snippets require [viz] and are
skipped, not failed, where it is absent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
cats_diagnostics_analysis.py, cats_vs_rws_tutorial.py,
thrombin_recovery_benchmark.py and the empty library_enumeration_demo.py
were untracked working files whose fate was deliberately deferred; an
over-broad 'git add -A tutorials' in the docstring commit swept them in.
They still use 1.x APIs (StandardWarmupConfig, max_resamples, pandas)
and are not part of 2.0. Files stay on disk, untracked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
extending.rst: the contract for each of the three base classes -- the
kwargs select_reagent receives, the hooks the sampler probes with
hasattr, the attributes it reads off a warmup -- and how to reuse the
_thermal mixins. The custom-strategy example is a snippet the suite
runs (a GMIC-mixin strategy driving a real search). Also: how the
package is laid out and why imports stay lazy.

tutorials.rst: card gallery of the nine tracked marimo notebooks with
what each exercises (marimo files cannot be rendered by myst-nb).

changelog.md: MyST include of CHANGELOG.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
index.rst: one sentence, six cards in dependency order (Library ->
Scoring -> Search -> Scale -> Inspect -> Visualise), four smaller cards
(Extend, Reference, Theory, Tutorials), the ten-minute quickstart
pulled from the same snippet the README shows and the suite runs,
install extras. Hidden toctrees drive the sidebar.

README: badge row deep-links to the guides and tutorials; the evaluator
table gains CustomEvaluatorConfig; the tutorial table lists all nine
notebooks (was four); doc links point at the search guide, reference
and theory pages instead of the site root.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
The word survived in two places after the redesign and meant the wrong
thing in both.

Theory pages: the derivations of standard Thompson Sampling and the
published RWS (Zhao et al. 2025) are the baselines CATS and TT-TS are
measured against and stay -- but the headings said 'Legacy', which now
reads as 'the deleted code'. Relabelled as Baselines / Published RWS,
with a note at the top of section 4 saying the 1.x implementations
were removed and where each baseline lives now (GreedyConfig; 1.2.0).
Section 4.2.5 claimed Boltzmann-weighted updates are 'Legacy Only' and
that CATS uses uniform updates -- false: the recommended presets run
with use_boltzmann_weighting=True and the 86.1%/85.5% figures were
measured that way. Rewritten as the switch it is, keeping Theorem 4.1
and stating the trade-off it captures.

Source docstrings that autodoc carries into the reference described
live features as legacy: EnhancedWarmup ('the legacy warmup approach'
-- it is the default), use_boltzmann_weighting ('legacy RWS'),
adaptive_temperature ('legacy-inspired'), the Shannon criticality
metric. Reworded. The only remaining mention is presets.py saying
legacy_rws was removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Aakankschit Nandkeolyar and others added 2 commits September 10, 2026 08:16
Header: engineering-interlude note (hypothesis unchanged; 2.0 removals
point at CHANGELOG; Boltzmann weighting kept; HPC3 runners need
porting). Established Results: 2.0 outcome; Boltzmann is the
production update rule. Ruled Out: two entries with Heptabase cards
(46511b3d: deleting Boltzmann as 'legacy' -- rejected on verification;
bb22697e: Sphinx autodoc traps with lazy hubs). Open Questions: unseeded
EnhancedWarmup, three skipped search-phase tests, API warts from the
docs pass, benchmark-data storage + HPC3 script porting.

Session log trimmed to the 10 most recent entries + this session; 21
older entries archived to docs/handoffs/session-archive-2026-05.md
(appended) and session-archive-2026-06.md (new).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGA4NaBZPsgXgze4qPnmND
Under Linux's default fork start method a worker rebuilding a
LookupEvaluator deadlocked in polars.read_csv: the child inherits the
parent's Rayon thread pool without its threads. This hung every
processes > 1 run and left the CI test job stuck in
test_parallel_matches_sequential until the 30-minute timeout.
macOS/Windows default to spawn, so it never reproduced locally.

ParallelEvaluator now uses multiprocessing.get_context("spawn"),
matching the pool in library_enumeration. Verified by forcing fork
globally: the 14 parallel-evaluation tests hang without this change
and pass in under 2 s with it; full suite 326 passed, 5 skipped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XqsaX2SHzvmoeHmbAu6F8
@aakankschit
aakankschit merged commit f955b9f into main Sep 10, 2026
4 checks passed
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.

1 participant