oc_chat
Loading...
Searching...
No Matches
encoder_classifier Namespace Reference

Classes

class  TrainConfig

Functions

list[dict[str, str]] read_jsonl (Path path)
frozenset[str] held_out_commands (Path bench_dir)
list[dict[str, str]] load_split (Path bench_dir, str name, frozenset[str] held_out)
dict[str, int] label_counts (list[dict[str, str]] rows)
list[list[dict[str, str]]] epoch_batches (list[dict[str, str]] rows, int batch, random.Random rng)
list[list[int]] tokenise (list[str] commands, object tokenizer, int max_length)
tuple[str,...] tokenise_keys (object tokenizer)
int full_vocab_size (object tokenizer)
tuple[list[int], dict[int, int]] prune_vocab (list[str] corpus, object tokenizer, int reserve=DEFAULT_VOCAB_RESERVE, int max_length=DEFAULT_MAX_LENGTH)
float token_coverage (list[str] commands, object tokenizer, set[int]|list[int] kept, int max_length=DEFAULT_MAX_LENGTH)
int resolve_max_length (list[str] commands, object tokenizer, int requested, int fallback=DEFAULT_MAX_LENGTH)
str cache_key (Path corpus_path, str tokenizer_digest, int max_length)
list[list[int]]|None load_cached_ids (Path cache_root, str key)
Path store_cached_ids (Path cache_root, str key, list[list[int]] rows)
list[int] remap_lookup (dict[int, int] remap, int unknown_id, int size)
list[dict[str, str]] validation_subset (list[dict[str, str]] rows, int size, int seed=DEFAULT_SUBSET_SEED)
dict[str, float] probabilities (list[float] logits, float temperature=1.0)
float brier (dict[str, float] probs, str truth)
float mean_negative_log_likelihood (list[list[float]] logits, list[int] labels, float temperature, list[float]|None weights=None)
float fit_temperature (list[list[float]] logits, list[int] labels, list[float]|None weights=None, float low=0.05, float high=20.0)
dict[str, float|int] calibration_report (list[list[float]] logits, list[dict[str, str]] rows, float temperature)
list[list[float]] cost_matrix (float alpha=DEFAULT_ALPHA)
float expected_cost_of (dict[str, float] probs, str pred, list[list[float]] costs)
str min_cost_verdict (dict[str, float] probs, list[list[float]] costs)
str decide (dict[str, float] probs, str decision=DEFAULT_DECISION, list[list[float]]|None costs=None)
float expected_cost (list[list[float]] prob_rows, list[int] labels, list[list[float]] costs)
float stopping_value (dict[str, float|int] record, str metric=DEFAULT_STOP_METRIC)
dict[str, float|int|bool] select_best_epoch (list[tuple[float, float]] pairs, str metric=DEFAULT_STOP_METRIC, int patience=1, float min_delta=EARLY_STOP_MIN_DELTA)
str other_stop_metric (str metric)
bool grants_more_permission (str truth, str pred)
dict[str, int] confident_error_counts (list[dict[str, object]] rows, tuple[float,...] thresholds=CONFIDENT_THRESHOLDS)
str _normalised_program (str token)
bool _is_short_cluster (str token)
str|None strip_recursive_option (str command)
tuple[list[dict[str, str]], int] relabel_recursive_allow (list[dict[str, str]] rows, object classify)
object gate_classifier (Path sandbox_root)
dict[str, object] result_row (dict[str, str] case, list[float] logits, float temperature, float elapsed_ms, str decision=DEFAULT_DECISION, list[list[float]]|None costs=None)
None write_result_file (Path path, str model, str condition, list[dict[str, object]] rows, dict[str, object] provenance)
str file_digest (Path path)
str weights_digest (Path model_dir)
tuple[str, bool] verify_tokenizer_vocab (Path tokenizer_dir, str backbone, Path hf_home)
tuple[object, object, object] _require_torch ()
str resolve_device (str requested=DEFAULT_DEVICE)
int peak_device_memory (str device)
str describe_device (str device)
dict[str, object] _to_device (object encoded, str device)
object remap_table (dict[int, int] remap, int unknown_id, int size, str device)
object _remap_input_ids (object input_ids, object table)
object cost_tensor (list[list[float]] costs, str device)
object expected_cost_term (object logits, object targets, object table)
int slice_embeddings (object model, list[int] kept, int pad_row)
dict[str, object] _collate (list[list[int]] rows, int pad_id, tuple[str,...] extra_keys, str device)
object|None _saved_remap_table (Path model_dir, str device)
object _load_tokenizer (Path tokenizer_dir)
list[list[float]] _forward_logits (object model, object tokenizer, list[str] commands, int max_length, int batch, str device="cpu", object|None table=None)
float score_full_validation (Path model_dir, list[dict[str, str]] rows, object tokenizer, int max_length, int batch, str device, object|None table)
dict[str, object] train (TrainConfig config)
dict[str, float|int] calibrate (Path model_dir, Path corpus_dir, int batch=DEFAULT_BATCH, int max_length=DEFAULT_MAX_LENGTH, int threads=DEFAULT_THREADS, str device=DEFAULT_DEVICE)
dict[str, object] evaluate (Path model_dir, Path cases_path, str condition, Path out_path, str model_name, int batch=1, int max_length=DEFAULT_MAX_LENGTH, int threads=DEFAULT_THREADS, str device=DEFAULT_DEVICE, str decision=DEFAULT_DECISION, float alpha=DEFAULT_ALPHA)
dict[str, object] relabel (Path bench_dir, Path out_dir)
Path _bench_dir ()
argparse.ArgumentParser _build_parser ()
int main (list[str]|None argv=None)

Variables

tuple LABELS = ("allow", "confirm", "deny")
tuple PERMISSIVENESS = ("deny", "confirm", "allow")
float DEFAULT_ALPHA = 1.0
float DEFAULT_COST_WEIGHT = 0.0
tuple DECISION_CHOICES = ("argmax", "min-cost")
str DEFAULT_DECISION = "argmax"
tuple STOP_METRIC_CHOICES = ("ce", "cost")
str DEFAULT_STOP_METRIC = "ce"
tuple CONFIDENT_THRESHOLDS = (0.9, 0.99)
int DEFAULT_SEED = 7
int DEFAULT_MAX_LENGTH = 64
int DEFAULT_BATCH = 32
int DEFAULT_LEARNING_RATE = 3e-5
int DEFAULT_MAX_EPOCHS = 4
float DEFAULT_WARMUP_SHARE = 0.1
int DEFAULT_THREADS = 8
tuple DEVICE_CHOICES = ("auto", "cpu", "cuda")
str DEFAULT_DEVICE = "auto"
str VOCAB_PRUNE_FILE = "vocab_prune.json"
int DEFAULT_VOCAB_RESERVE = 2000
 DEFAULT_CACHE_ROOT = Path(r"G:\Temp\claude\g--PythonApps-option-c\harness\bench_cache")
int DEFAULT_SUBSET_ROWS = 1000
int DEFAULT_SUBSET_SEED = 294
int FAST_MAX_LENGTH = 48
float DEFAULT_BUDGET_SECONDS = 3600.0
int EARLY_STOP_MIN_DELTA = 1e-4
int BUCKET_BATCHES = 50
 DEFAULT_MODEL_ROOT
 DEFAULT_TOKENIZER_DIR
 DEFAULT_HF_HOME = Path(r"G:\Temp\claude\g--PythonApps-option-c\harness\hf_home")
frozenset LISTING_PROGRAMS = frozenset({"ls", "dir"})
str RECURSIVE_OPTION = "R"

Detailed Description

A small DeBERTa-v3 encoder fine-tuned on the gate-labelled corpus, calibrated.

Purpose
-------
The 2026-09-07 classifier note proposed discriminative encoder classifiers as
gates: tens to a few hundred million parameters, CPU milliseconds, a typed
verdict with a probability, trained on our own corpus. The 2026-09-17 session
tested the hosted end of that idea and the zero-shot end of it; this module
tests the proposal itself, which is a small encoder FINE-TUNED on the
gate-labelled commands plan 288 generated. It trains, it calibrates its logits
with one scalar, and it writes result files in the bench schema so the same
scorer reads it beside Jev, DeepSeek and the token floor.

Four commands, in the order a run uses them::

    train      --backbone <hf id> --out <dir>      # fine-tune, early-stopped
    calibrate  --model <dir>                       # fit one temperature
    evaluate   --model <dir> --cases <file>        # write a result file
    relabel    --out <dir>                         # the policy-change probe

``train``, ``calibrate`` and ``evaluate`` need torch and transformers and run
under a SCRATCH HARNESS venv; ``relabel`` needs the argv gate and runs under
the PROJECT venv. That split is why torch and transformers are imported inside
the functions that use them rather than at module scope: the tests in
``tests/test_290_encoder.py`` and ``tests/test_294_speed.py`` exercise the
loader, the temperature fit, the vocabulary pruning, the tensor cache, the
relabel filter and the result writer in the project venv, where no torch
exists, and an import at module scope would put every one of them out of reach.

Two scratch venvs, and which one to use
---------------------------------------
Plan 290 ran on the CPU venv at ``...\\harness\\.venv``. Plan 294 added a second
one at ``...\\harness_cuda`` carrying ``torch==2.14.*+cu126``, because the host's
GTX 1060 is a Pascal card (compute capability 6.1) and **the CUDA 12.6 wheel of
PyTorch 2.14 is the last prebuilt build that still carries ``sm_61`` kernels**:
PyTorch dropped Pascal from its CUDA 12.8 and 12.9 wheels at release 2.8 and
CUDA 13 cannot build them. Both venvs stay; the CPU one is what keeps every
number plan 290 produced reproducible, and ``--device cpu`` reproduces a CPU run
inside the CUDA venv as well.

Run the trainer from the subproject root with the harness interpreter, with
``HF_HOME`` and ``HF_HUB_OFFLINE=1`` set in the shell::

    <harness>\\python.exe bench/argv_policy/baselines/encoder_classifier.py train
        --backbone microsoft/deberta-v3-xsmall --out <scratch>/bench_models/xsmall-7

Model directories, their checkpoints and the raw training logs live under
:data:`DEFAULT_MODEL_ROOT` on ``G:`` and are never committed; only the result
JSON and a copy of the training log go into the worktree.

The tokenizer
-------------
``AutoTokenizer.from_pretrained("microsoft/deberta-v3-xsmall")`` cannot be
loaded in the harness venv: the snapshot ships only ``spm.model``, and
converting that to a fast tokenizer needs protobuf and sentencepiece, neither
of which is installed (and installing is not this plan's to do). The
``MoritzLaurer/deberta-v3-base-zeroshot-v2.0`` snapshot in the same cache
ships an already-converted ``tokenizer.json``, and its ``spm.model`` is
BYTE-IDENTICAL to both microsoft backbones' -- SHA-256
``c679fbf93643d19aab7ee10c0b99e460bdbc02fedf34b92b05af343b4af586fd`` for all
three. So the tokenizer is loaded from that directory and
:func:`verify_tokenizer_vocab` re-checks the digest equality at every training
run rather than trusting this paragraph.

Pricing the direction of an error (plan 298)
--------------------------------------------
Cross-entropy prices an ``allow`` where the gate says ``deny`` exactly as it
prices a ``deny`` where the gate says ``allow``. The bench does not: the column
it is read by counts the errors that GRANT MORE PERMISSION than the gate, and
the other kind costs a human one unnecessary confirmation. Plan 298 puts that
asymmetry into the arithmetic as one cost matrix and two levers over it.

``--alpha A`` sets the matrix: zero on the diagonal, ``A`` where the prediction
is more permissive than the truth, ``1`` where it is less. Then:

- ``evaluate --decision min-cost`` reads the verdict minimising expected cost
  out of the calibrated probabilities. It retrains nothing and rewrites no
  probability -- only the ``pred`` field moves -- so it costs one flag.
- ``train --cost-weight B`` adds ``B`` times the expected cost under that same
  matrix to the training loss.

Both default to today's behaviour exactly, not approximately: ``--alpha 1.0``
makes every off-diagonal cell ``1``, under which the min-cost verdict and the
argmax verdict agree on every input including ties, and ``--cost-weight 0.0``
removes the loss term altogether.

Watching the same column the objective prices (plan 300)
--------------------------------------------------------
Plan 298 held the stopping rule fixed on validation cross-entropy so that the
objective was the only variable, and measured what that cost: at
``--cost-weight 3`` the run stopped at epoch 2 and checkpointed an undertrained
model, because an objective that prices the direction moves AWAY from
cross-entropy by construction and a rule watching cross-entropy reads that
movement as a run that has stopped improving. The two pieces are supplied here.

- ``train --stop-metric cost`` makes early stopping and checkpoint selection
  watch the subset validation EXPECTED COST under the same ``--alpha`` matrix
  the loss term prices with, rather than the subset cross-entropy. Both figures
  are computed and logged every epoch whichever one stops the run, so an
  after-the-fact reader can see the epoch the other metric would have kept --
  and :func:`select_best_epoch` states it in the training record rather than
  leaving it to be inferred from the log.
- ``evaluate`` counts the PERMISSION-GRANTING errors a result file makes
  confidently, at 0.9 and at 0.99 top probability, into its provenance block.
  Plan 298 found that class by hand and it is the class the escalation
  threshold cannot reach: an error the model is sure about is not escalated and
  no decision rule over a calibrated distribution moves it. Counting it in the
  file makes it a column of the table rather than an afternoon's grep.

``--stop-metric ce`` is the default and is plan 290's rule unchanged, so an
unflagged run is still the run every earlier tag on this bench was produced by;
the counts are additive provenance and leave the row shape ``score.py`` reads
untouched.

Responsibilities
----------------
- :func:`held_out_commands` / :func:`load_split` / :func:`label_counts` --
  the corpus loader, with the hand-case guard.
- :func:`epoch_batches` -- one epoch of length-bucketed minibatches.
- :func:`resolve_device` -- plan 294 P1's device selection.
- :func:`prune_vocab` / :func:`token_coverage` -- plan 294 P2's vocabulary
  pruning, in pure Python.
- :func:`remap_lookup` / :func:`remap_table` -- the pruned id space.
- :func:`cache_key` / :func:`load_cached_ids` / :func:`store_cached_ids` /
  :func:`validation_subset` / :func:`resolve_max_length` -- plan 294 P3's
  tokenised-id cache and subset validation.
- :func:`fit_temperature` / :func:`mean_negative_log_likelihood` /
  :func:`probabilities` / :func:`brier` -- calibration, in pure Python.
- :func:`cost_matrix` / :func:`expected_cost_of` / :func:`min_cost_verdict` /
  :func:`decide` / :func:`expected_cost` -- plan 298's direction-weighted cost
  matrix, its decision rule and its loss term, in pure Python.
- :func:`cost_tensor` / :func:`expected_cost_term` -- the same loss term on
  tensors, which is what the training loop actually calls.
- :func:`stopping_value` / :func:`select_best_epoch` -- plan 300 P1's
  direction-aware stopping rule, in pure Python.
- :func:`grants_more_permission` / :func:`confident_error_counts` -- plan 300
  P2's confident permission-granting error count, in pure Python.
- :func:`strip_recursive_option` / :func:`relabel_recursive_allow` /
  :func:`gate_classifier` -- the policy-change probe's documented relabel.
- :func:`result_row` / :func:`write_result_file` -- the plan-288 result schema.
- :func:`train` / :func:`calibrate` / :func:`evaluate` -- the torch commands.
- :func:`main` -- the CLI.

Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
    L2 - command lifecycle (training start and finish, files written)
    L3 - per-epoch validation loss, per-case-set agreement, fitted temperature
    L4 - module load

Contracts
---------
- Read-only with respect to the committed corpus, the case sets and the gate:
  the policy-change probe writes a RELABELLED COPY under the scratch root and
  never edits a committed file.
- The relabelled labels come from the unmodified gate applied to a rewritten
  command, never from a hand edit of a verdict.
- Bitwise reproduction is not claimed (CPU thread scheduling reorders float
  reductions); a run is IDENTIFIABLE instead -- every result file carries the
  backbone, the seed, the epoch count, the training wall time, the parameter
  count and the SHA-256 of the saved weights.
- Nothing from either case set touches training or calibration.
- Console output is ASCII only; commands are printed through :func:`ascii`.
- No dependency enters any ``pyproject.toml``; torch and transformers are
  imported lazily and only exist in the scratch harness venv.

Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- torch (LAZY, harness venv only: tensors, AdamW, the forward and backward pass)
- transformers (LAZY, harness venv only: AutoTokenizer and AutoModelForSequenceClassification)
- oc_chat.tools._argv_policy (LAZY, project venv only: the gate the relabel asks)

Function Documentation

◆ _bench_dir()

Path encoder_classifier._bench_dir ( )
protected
``bench/argv_policy`` -- the directory holding the corpus and the cases.

Definition at line 2020 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _build_parser()

argparse.ArgumentParser encoder_classifier._build_parser ( )
protected
Construct the CLI argument parser.

Definition at line 2026 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _collate()

dict[str, object] encoder_classifier._collate ( list[list[int]] rows,
int pad_id,
tuple[str, ...] extra_keys,
str device )
protected
Pad cached ids into the tensors the model's forward pass expects.

*extra_keys* mirrors whatever the tokenizer itself emits beside the ids and
the mask -- ``token_type_ids`` for this tokenizer -- as zeros, so a cached
batch and a freshly tokenised one are the same call.

Definition at line 1333 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _forward_logits()

list[list[float]] encoder_classifier._forward_logits ( object model,
object tokenizer,
list[str] commands,
int max_length,
int batch,
str device = "cpu",
object | None table = None )
protected
Logits for every command, in batches, in evaluation mode.

*table* is plan 294 P2's pruned-vocabulary lookup: when the model's
embedding table has been sliced, the ids the tokenizer produces are the FULL
vocabulary's and have to be carried through the map before they index the
sliced table, or every id past the kept count is out of range.

Definition at line 1383 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _is_short_cluster()

bool encoder_classifier._is_short_cluster ( str token)
protected
Whether *token* is a short-option cluster such as ``-la``.

Definition at line 975 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _load_tokenizer()

object encoder_classifier._load_tokenizer ( Path tokenizer_dir)
protected
Load the converted DeBERTa-v3 fast tokenizer from a local directory.

Definition at line 1376 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _normalised_program()

str encoder_classifier._normalised_program ( str token)
protected
The program name the gate would read out of *token*.

Definition at line 968 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _remap_input_ids()

object encoder_classifier._remap_input_ids ( object input_ids,
object table )
protected
Carry a batch of full-vocabulary ids through a :func:`remap_table`.

Definition at line 1279 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _require_torch()

tuple[object, object, object] encoder_classifier._require_torch ( )
protected
Import torch and transformers, or say which interpreter is needed.

Definition at line 1193 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ _saved_remap_table()

object | None encoder_classifier._saved_remap_table ( Path model_dir,
str device )
protected
The lookup table for a model trained with a pruned vocabulary, or ``None``.

``train`` writes :data:`VOCAB_PRUNE_FILE` beside the weights when and only
when it pruned, so its presence is what tells ``calibrate`` and ``evaluate``
that the ids a tokenizer hands them are not the ids this model's embedding
table is indexed by. A model trained without pruning has no such file and
every id goes through untouched.

Definition at line 1355 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _to_device()

dict[str, object] encoder_classifier._to_device ( object encoded,
str device )
protected
Every tensor of a tokenizer's output, moved onto *device*.

Definition at line 1261 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ brier()

float encoder_classifier.brier ( dict[str, float] probs,
str truth )
The multi-class Brier score of one forecast (``score.brier_row``).

Kept here rather than imported because ``score.py`` sits one directory up
and this module is run as a script from the harness venv; the arithmetic is
two lines and ``tests/test_290_encoder.py`` asserts the two agree.

Definition at line 606 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ cache_key()

str encoder_classifier.cache_key ( Path corpus_path,
str tokenizer_digest,
int max_length )
The cache identity of one tokenised split.

The corpus file's own SHA-256 is in the key, so a regenerated corpus
invalidates the cache instead of training the next run on the previous
corpus's ids -- which would be a silent wrong answer, not a crash.

Definition at line 525 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ calibrate()

dict[str, float | int] encoder_classifier.calibrate ( Path model_dir,
Path corpus_dir,
int batch = DEFAULT_BATCH,
int max_length = DEFAULT_MAX_LENGTH,
int threads = DEFAULT_THREADS,
str device = DEFAULT_DEVICE )
Fit one temperature on the validation split and record what it moved.

Plan 294 P3 validates on a 1,000-row subset DURING training, for speed; the
temperature is still fitted on the whole 3,000-row split here, because a
calibration scalar fitted on a third of the rows is a third as well
determined and costs one forward pass to get right.

Definition at line 1799 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calibration_report()

dict[str, float | int] encoder_classifier.calibration_report ( list[list[float]] logits,
list[dict[str, str]] rows,
float temperature )
NLL, Brier and agreement on the validation split, before and after.

Definition at line 684 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ confident_error_counts()

dict[str, int] encoder_classifier.confident_error_counts ( list[dict[str, object]] rows,
tuple[float, ...] thresholds = CONFIDENT_THRESHOLDS )
Plan 300 P2: how many permission-granting errors were made CONFIDENTLY.

Returns the total, and the count at or above each threshold's top
probability. The class matters because it is the one nothing downstream can
catch: escalation fires BELOW its threshold, so an error at 0.99 is not
escalated; and a min-cost reading moves a verdict only where the
distribution leaves enough mass elsewhere to move, which at 0.999 it does
not. Plan 298 found five of ``small``'s thirteen at 0.9 or better and three
at 0.999 or better by hand; this makes it a number every result file
carries.

A row with no usable forecast counts towards the total and towards no
threshold, which is the same treatment ``score.py`` gives it in the Brier
column: a missing probability is not evidence of a confident mistake.

Definition at line 924 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cost_matrix()

list[list[float]] encoder_classifier.cost_matrix ( float alpha = DEFAULT_ALPHA)
Plan 298 P1: ``COST[true][pred]``, both axes in :data:`LABELS` order.

Zero on the diagonal; *alpha* in every cell where the prediction grants MORE
permission than the gate's verdict; ``1.0`` in every cell where it grants
less. At *alpha* ``1.0`` every off-diagonal cell is ``1.0``, which is the
matrix a plain cross-entropy objective and an argmax decision rule already
imply -- which is why that is the default and why it reproduces every number
on this bench rather than approximating it.

The asymmetry is the whole of this plan. An ``allow`` where the gate says
``deny`` runs something the gate refused; a ``deny`` where the gate says
``allow`` costs a human one unnecessary confirmation. Cross-entropy prices
those two mistakes identically. The gate does not, and neither does the
column this bench is read by.

Definition at line 712 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ cost_tensor()

object encoder_classifier.cost_tensor ( list[list[float]] costs,
str device )
A :func:`cost_matrix` as a float tensor on *device*, built once per run.

Definition at line 1285 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decide()

str encoder_classifier.decide ( dict[str, float] probs,
str decision = DEFAULT_DECISION,
list[list[float]] | None costs = None )
The verdict *decision* reads out of one calibrated distribution.

The two rules are kept behind one function because ``result_row`` must not
grow a branch: a result file differs under the two rules in its ``pred``
field and in nothing else, and that stays true more easily when the choice
is made in one place.

Definition at line 772 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ describe_device()

str encoder_classifier.describe_device ( str device)
A one-line description of *device* for a log line and a result file.

Definition at line 1251 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ epoch_batches()

list[list[dict[str, str]]] encoder_classifier.epoch_batches ( list[dict[str, str]] rows,
int batch,
random.Random rng )
One epoch of minibatches: a permutation of *rows*, length-bucketed.

An epoch is a permutation, so the class balance a batch sequence sees is
the corpus's own and no class weighting is needed. Within a chunk of
:data:`BUCKET_BATCHES` batches the rows are sorted by command length before
being cut into batches, and the batch order is then shuffled: padding
follows the chunk rather than the longest command in the epoch, which on
this corpus is the difference between 20.6 and 17.1 minutes per epoch, and
the shuffle keeps the gradient sequence stochastic.

Definition at line 389 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ evaluate()

dict[str, object] encoder_classifier.evaluate ( Path model_dir,
Path cases_path,
str condition,
Path out_path,
str model_name,
int batch = 1,
int max_length = DEFAULT_MAX_LENGTH,
int threads = DEFAULT_THREADS,
str device = DEFAULT_DEVICE,
str decision = DEFAULT_DECISION,
float alpha = DEFAULT_ALPHA )
Predict a case set and write its result file, timing every decision.

At ``batch=1`` the clock runs around tokenise-plus-forward for one command,
which is the per-decision latency a gate would pay. At ``batch>1`` the
clock runs around the whole batch and the per-row figure is the amortised
one, which is the throughput reading rather than the latency reading.

*decision* and *alpha* are plan 298 P2's rule. They are a property of the
READING and not of the model, so both go into the provenance block: two
result files from one checkpoint under two rules are otherwise
indistinguishable except by their verdicts, and the scorer reports no field
that would say which rule produced which.

Plan 300 P2 adds :func:`confident_error_counts` to that same block. It goes
in the PROVENANCE and not into the rows on purpose: ``score.py`` reads the
row shape and a new per-row field would change what every consumer of a
result file sees, whereas a provenance key is additive and the scorer never
looks at it. The counts are recomputable from the rows by anyone who wants
them at another threshold, which is why the file carries the summary rather
than a flag per row.

Definition at line 1847 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ expected_cost()

float encoder_classifier.expected_cost ( list[list[float]] prob_rows,
list[int] labels,
list[list[float]] costs )
Plan 298 P3's training term, written out in plain Python.

Per row ``sum_pred p[pred] * COST[true][pred]``, averaged over the batch so
the term lands on the same scale as the mean cross-entropy it is added to
and ``--cost-weight`` therefore means the same thing at any batch size.

This function is the DEFINITION and :func:`expected_cost_term` is the fast
copy of it; ``tests/test_298_direction.py`` asserts the two agree on a toy
batch, which is the only reason the tensor version can be trusted inside a
run whose per-step output nobody checks by hand.

Definition at line 792 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ expected_cost_of()

float encoder_classifier.expected_cost_of ( dict[str, float] probs,
str pred,
list[list[float]] costs )
What predicting *pred* costs in expectation under the forecast *probs*.

``sum_true p(true) * COST[true][pred]`` -- the quantity plan 298 P2's rule
minimises, named so a test can assert the arithmetic directly rather than
only through the verdict it happens to produce.

Definition at line 740 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ expected_cost_term()

object encoder_classifier.expected_cost_term ( object logits,
object targets,
object table )
Plan 298 P3's training term on tensors: the batch's mean expected cost.

``softmax(logits)`` is the model's own forecast, so the term is
differentiable in the logits and pushes probability mass off the verdicts
the matrix prices highly -- not merely off the wrong ones, which is what
cross-entropy alone does. ``table[targets]`` selects each row's true-verdict
cost row, and that gather is the whole of the indexing.

:func:`expected_cost` is the definition this reproduces; the witness in
``tests/test_298_direction.py`` asserts the two agree on a toy batch.

Definition at line 1292 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ file_digest()

str encoder_classifier.file_digest ( Path path)
The SHA-256 of one file, which is how a trained run is identified.

Definition at line 1116 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ fit_temperature()

float encoder_classifier.fit_temperature ( list[list[float]] logits,
list[int] labels,
list[float] | None weights = None,
float low = 0.05,
float high = 20.0 )
Fit one temperature by minimising NLL, by golden-section search.

Plan 290 P3 asks for the negative log-likelihood to be minimised over one
scalar with the optimisation written out rather than called from a fitting
library, and W1 asks for a fit that runs in the project venv, where there
is no torch. A golden-section search over log-temperature satisfies both:
the objective is unimodal in log T, the search needs no derivative, and
eighty iterations close the bracket to about 1e-7.

Definition at line 647 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ full_vocab_size()

int encoder_classifier.full_vocab_size ( object tokenizer)
How many ids the tokenizer can emit, counting any added tokens.

Definition at line 434 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ gate_classifier()

object encoder_classifier.gate_classifier ( Path sandbox_root)
A ``command -> (verdict, reason)`` callable backed by the real gate.

Imported lazily: the argv gate lives in the ``oc_chat`` package, which the
scratch harness venv cannot import, and only ``relabel`` needs it.

Definition at line 1044 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ grants_more_permission()

bool encoder_classifier.grants_more_permission ( str truth,
str pred )
Whether predicting *pred* where the gate said *truth* grants MORE permission.

``score.py``'s :func:`error_direction` in a boolean, and asserted equal to
it in ``tests/test_300_stopping.py`` rather than left as two opinions about
which way is dangerous. An unrecognised prediction counts as granting more,
for the reason the scorer gives: understating that column is the one
direction this bench must never round in.

Definition at line 906 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ held_out_commands()

frozenset[str] encoder_classifier.held_out_commands ( Path bench_dir)
Every command in the two case sets, which no training row may repeat.

Definition at line 349 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ label_counts()

dict[str, int] encoder_classifier.label_counts ( list[dict[str, str]] rows)
How many rows carry each verdict.

Definition at line 383 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ load_cached_ids()

list[list[int]] | None encoder_classifier.load_cached_ids ( Path cache_root,
str key )
The tokenised split cached under *key*, or ``None`` when it is absent.

Definition at line 537 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ load_split()

list[dict[str, str]] encoder_classifier.load_split ( Path bench_dir,
str name,
frozenset[str] held_out )
Load one corpus split, refusing any row that is a held-out case.

``gen_corpus.py`` already drops the case sets at generation time, so this
guard should never fire -- which is exactly why it is worth asserting here:
a hand case that reached training would raise every agreement figure on
this bench and nothing downstream would look wrong.

Definition at line 362 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int encoder_classifier.main ( list[str] | None argv = None)
CLI entry point: train, calibrate, evaluate, or relabel.

Definition at line 2116 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mean_negative_log_likelihood()

float encoder_classifier.mean_negative_log_likelihood ( list[list[float]] logits,
list[int] labels,
float temperature,
list[float] | None weights = None )
Mean NLL of *logits* divided by *temperature* against *labels*.

*weights* exist for the witness, not for the run: weighting each logit row
by the true probability of each class turns this into the EXPECTED NLL,
whose minimiser over the scalar is exactly the temperature the logits were
scaled by, which is what lets the test assert a known answer to two
decimals instead of a sampling interval.

Definition at line 618 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ min_cost_verdict()

str encoder_classifier.min_cost_verdict ( dict[str, float] probs,
list[list[float]] costs )
Plan 298 P2: the verdict with the lowest expected cost under *probs*.

``argmin_pred sum_true p(true) * COST[true][pred]``. This is the cheap
lever: it changes no weights and touches no probability, only which verdict
is read out of one, so a model already trained and calibrated can be made
more cautious for the price of a second pass over its own output.

A tie breaks towards the earlier :data:`LABELS` column, which is precisely
how ``max`` breaks an argmax tie over the same dict. That matters more than
it looks: it is what makes this rule agree with the argmax rule on EVERY
input at *alpha* ``1.0``, rather than on every input that happens not to be
tied, so the default really is the old behaviour and not merely close to it.

Definition at line 754 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ other_stop_metric()

str encoder_classifier.other_stop_metric ( str metric)
The stopping metric *metric* is not, which is what the record compares.

Definition at line 895 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ peak_device_memory()

int encoder_classifier.peak_device_memory ( str device)
Peak bytes torch allocated on *device* since the last reset, or ``0``.

``max_memory_allocated`` rather than ``nvidia-smi``: the card also carries
the desktop and every browser on this host, so the only figure that means
"what this training run needed" is torch's own allocator high-water mark.

Definition at line 1237 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ probabilities()

dict[str, float] encoder_classifier.probabilities ( list[float] logits,
float temperature = 1.0 )
The temperature-scaled softmax of one logit row, keyed by verdict.

Definition at line 596 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ prune_vocab()

tuple[list[int], dict[int, int]] encoder_classifier.prune_vocab ( list[str] corpus,
object tokenizer,
int reserve = DEFAULT_VOCAB_RESERVE,
int max_length = DEFAULT_MAX_LENGTH )
Plan 294 P2: the vocabulary rows worth keeping, and the map onto them.

DeBERTa-v3-xsmall carries 70.8M parameters of which the 128,100-row
embedding table at width 384 is about 49M -- two thirds of the model
devoted to pieces this corpus never emits. The kept set is every id the
corpus actually produces, plus every special token, plus a reserve of the
most frequent ids that do NOT occur, so an unseen but plausible piece still
has a row of its own rather than collapsing onto the unknown token.

Returns the kept ids ASCENDING and a map from old id to its position in
that list. Ascending order is not cosmetic: it keeps the control symbols at
the front in their original relative order, so the padding id survives the
remap as itself and a saved config's ``pad_token_id`` stays true.

Definition at line 443 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_jsonl()

list[dict[str, str]] encoder_classifier.read_jsonl ( Path path)
Read a JSON-lines file into a list of rows.

Definition at line 342 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ relabel()

dict[str, object] encoder_classifier.relabel ( Path bench_dir,
Path out_dir )
Write the policy-change probe's relabelled copy of the corpus.

The copy goes under *out_dir* -- never over a committed file -- and is a
self-consistent bench corpus under the changed policy: both corpus splits
and both case sets, each under its canonical name, so ``train
--corpus-dir <out_dir>`` finds the held-out guard's case files and
``evaluate --cases <out_dir>/cases.json`` measures against the labels the
CHANGED policy implies rather than the committed ones. A report beside
them records the filter, the counts and the verdict movement.

Definition at line 1953 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ relabel_recursive_allow()

tuple[list[dict[str, str]], int] encoder_classifier.relabel_recursive_allow ( list[dict[str, str]] rows,
object classify )
Relabel every matched row by asking the gate about the stripped command.

Returns the new rows and how many verdicts actually moved. A matched row
whose verdict does not move is the interesting case and is kept, not
dropped: ``ls -laR /etc`` is still a deny after ``-R`` becomes allowed,
because the path is still outside the sandbox, and a blanket
deny-to-allow rewrite would have taught the model the opposite.

Definition at line 1013 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remap_lookup()

list[int] encoder_classifier.remap_lookup ( dict[int, int] remap,
int unknown_id,
int size )
The old-id to new-id lookup as a plain list, unknown-filled.

Every id the pruning dropped points at the unknown token, which is the
pruning's whole contract for a piece the corpus never showed. Built here in
pure Python rather than inside the tensor constructor so the contract is
assertable in the project venv, where there is no torch.

Definition at line 560 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ remap_table()

object encoder_classifier.remap_table ( dict[int, int] remap,
int unknown_id,
int size,
str device )
:func:`remap_lookup` as a tensor on *device*, built once per run.

A dict lookup per token would cost more than the forward pass it feeds, so
plan 294 P2's map is materialised as a tensor indexed by the old id.

Definition at line 1267 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_device()

str encoder_classifier.resolve_device ( str requested = DEFAULT_DEVICE)
The device a run will actually use, or a refusal saying why it cannot.

``auto`` is the default and reads the machine: CUDA when torch reports a
usable device, the CPU otherwise. ``cuda`` is an ASSERTION rather than a
preference -- if torch cannot see the card it raises, because the failure
mode this guards against is a run that silently takes the CPU path and is
read as a GPU measurement eighteen minutes later. ``cpu`` always succeeds
and is how the CUDA venv reproduces a plan-290 CPU number.

Definition at line 1207 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_max_length()

int encoder_classifier.resolve_max_length ( list[str] commands,
object tokenizer,
int requested,
int fallback = DEFAULT_MAX_LENGTH )
*requested* if it never truncates *commands*, else *fallback*.

Plan 294 P3 shortens the sequence from 64 to 48 because the corpus's
longest command is 44 tokens. That is a measured fact about a committed
file rather than a property of the task, so it is re-measured here: a
regenerated corpus carrying a longer command silently loses its tail
otherwise, and a truncated command is a mislabelled training row.

Definition at line 505 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ result_row()

dict[str, object] encoder_classifier.result_row ( dict[str, str] case,
list[float] logits,
float temperature,
float elapsed_ms,
str decision = DEFAULT_DECISION,
list[list[float]] | None costs = None )
One result row in the plan-288 schema, calibrated and timed.

*decision* is plan 298 P2's rule, defaulting to the argmax every result file
written before that plan carries. Note what it does NOT touch: ``probs`` and
``logits`` are the model's own output either way, so two result files
differing only in the rule differ only in ``pred``, and the Brier score and
the reliability bands the scorer computes are identical across the pair.
That is the property that lets the table read the rule's effect off the
agreement and direction columns alone.

Definition at line 1067 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ score_full_validation()

float encoder_classifier.score_full_validation ( Path model_dir,
list[dict[str, str]] rows,
object tokenizer,
int max_length,
int batch,
str device,
object | None table )
The WHOLE validation split's cross-entropy at the saved best checkpoint.

Plan 294 P3 validates each epoch on a 1,000-row subset, which is a
different number from plan 290's 3,000-row one and cannot be compared with
it. The best checkpoint is therefore reloaded once at the end and scored on
the full split, so the run still produces the figure the previous plan's
log can be read against.

Definition at line 1415 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_best_epoch()

dict[str, float | int | bool] encoder_classifier.select_best_epoch ( list[tuple[float, float]] pairs,
str metric = DEFAULT_STOP_METRIC,
int patience = 1,
float min_delta = EARLY_STOP_MIN_DELTA )
Plan 300 P1: which epoch a run watching *metric* keeps, and when it stops.

*pairs* is one ``(cross-entropy, expected cost)`` per epoch in epoch order,
in :data:`STOP_METRIC_CHOICES` order, which is how *metric* selects the
element to compare. Returns the 1-based best epoch (``0`` when no epoch ever
improved), the value it scored, how many epochs the run would have got
through, and whether patience ended it.

This is the loop's rule written out as a function, and it earns its place
twice. It is what W1 asserts on hand-written sequences, where the answer is
known and a real run's is not. And it is what the training record calls on
at the end with the OTHER metric, so the plan-300 table can say which epoch
a run would have checkpointed had it watched the other column -- the one
figure that separates "the stopping rule moved the model" from "the run
happened to differ". Run over the epochs one run actually produced: a run
watching the other metric might have stopped earlier and never seen the
later pairs, so the alternate epoch is a reading of THIS run's curve, not a
prediction of a run nobody made.

Definition at line 837 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ slice_embeddings()

int encoder_classifier.slice_embeddings ( object model,
list[int] kept,
int pad_row )
Replace the model's word embeddings with the *kept* rows only.

Returns how many rows the table held before. The classification head is a
pooler and a linear layer, so nothing is tied to this table and slicing it
is the whole of the change; ``config.vocab_size`` moves with it so that a
``save_pretrained`` round trip rebuilds the same shape.

Definition at line 1310 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stopping_value()

float encoder_classifier.stopping_value ( dict[str, float | int] record,
str metric = DEFAULT_STOP_METRIC )
Plan 300 P1: the figure a run watching *metric* compares for one epoch.

One function rather than a conditional expression in two places, because the
training loop and :func:`select_best_epoch` have to agree about which number
is being watched or the record's "the other metric would have chosen epoch
N" line is measuring something no run would have done.

Definition at line 819 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ store_cached_ids()

Path encoder_classifier.store_cached_ids ( Path cache_root,
str key,
list[list[int]] rows )
Write a tokenised split into the cache and return where it landed.

Definition at line 549 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ strip_recursive_option()

str | None encoder_classifier.strip_recursive_option ( str command)
*command* with the recursive listing option removed, or ``None``.

This is the whole of the policy change the probe measures: ``-R`` becomes
an allowed option of the Tier-1 listing commands, and nothing else moves.
Because the option carries no other meaning to the gate, the verdict of a
command under the changed policy is the verdict the UNMODIFIED gate gives
the same command with ``-R`` removed -- which is how
:func:`relabel_recursive_allow` derives every new label without editing
``_argv_policy.py`` and without hand-writing a verdict.

``None`` when the command is not a listing command carrying an unquoted
``-R``: a quoted ``'-R'`` is data, ``--reverse`` is a different option, and
``python -R`` is a real option of a different program in a different tier.

Definition at line 981 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ token_coverage()

float encoder_classifier.token_coverage ( list[str] commands,
object tokenizer,
set[int] | list[int] kept,
int max_length = DEFAULT_MAX_LENGTH )
The share of token OCCURRENCES in *commands* that a kept id covers.

Occurrences rather than distinct ids: one rare piece appearing once in one
hard case is not the same loss as a common piece appearing in a hundred,
and the figure that says whether pruning hurt the case sets is the one
weighted the way the case sets actually use the vocabulary.

Definition at line 485 of file encoder_classifier.py.

Here is the call graph for this function:

◆ tokenise()

list[list[int]] encoder_classifier.tokenise ( list[str] commands,
object tokenizer,
int max_length )
The token ids of every command, unpadded, truncated at *max_length*.

Definition at line 420 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ tokenise_keys()

tuple[str, ...] encoder_classifier.tokenise_keys ( object tokenizer)
Which tensors this tokenizer emits, asked of it rather than assumed.

Definition at line 428 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ train()

dict[str, object] encoder_classifier.train ( TrainConfig config)
Fine-tune one backbone on the corpus, early-stopped on a watched metric.

Writes the best epoch's weights, the tokenizer and a training record into
``config.out_dir``, and returns the record. The stopping rule is plan 290
P2's -- validation cross-entropy stops improving -- plus the budget guard
P2's one-hour wall-time limit implies: when another epoch would not fit,
the run stops at the end of the current one and the record says so, which
is the opposite of quietly overrunning the budget.

Plan 298 P3 adds ``config.cost_weight`` times :func:`expected_cost_term` to
the per-batch loss. Two deliberate limits on it. It is off at ``0.0``, so an
unflagged run is still plan 295's run. And the STOPPING rule was left on
plain validation cross-entropy even when the term was on: the recipe was
being held constant so that the objective was the only variable, and moving
the early-stopping criterion at the same time would have changed two things
and measured their sum.

Plan 300 P1 supplies the second thing, as its own flag.
``config.stop_metric`` chooses which validation figure early stopping and
checkpoint selection watch: ``"ce"`` is the rule above, unchanged and still
the default, and ``"cost"`` watches the subset validation expected cost
under the same ``config.alpha`` matrix -- the column a direction-weighted
objective is trying to move, and the one plan 298 measured a run being
checkpointed against. Both figures are computed every epoch whichever one
stops the run, the epoch log carries both, and the record says which epoch
the other metric would have kept. Nothing else moves: the full-split
cross-entropy is still scored on the reloaded best checkpoint, and the
temperature is still fitted by NLL afterwards, so the probabilities a
reading consumes are calibrated the way every earlier tag's were.

Definition at line 1441 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validation_subset()

list[dict[str, str]] encoder_classifier.validation_subset ( list[dict[str, str]] rows,
int size,
int seed = DEFAULT_SUBSET_SEED )
A fixed *size*-row sample of *rows*, the same one for every run.

The sample is drawn from a pinned seed and then restored to corpus order,
so the subset a run validates on depends on the seed alone and not on the
order the shuffle happened to produce.

Definition at line 575 of file encoder_classifier.py.

Here is the caller graph for this function:

◆ verify_tokenizer_vocab()

tuple[str, bool] encoder_classifier.verify_tokenizer_vocab ( Path tokenizer_dir,
str backbone,
Path hf_home )
Check the tokenizer's vocabulary is the backbone's own, by digest.

Returns the tokenizer's ``spm.model`` digest and whether a ``spm.model``
found in the backbone's cache directory matches it. A mismatch means the
tokenizer is the wrong one for the weights and training would be nonsense,
so the caller refuses rather than warning.

Definition at line 1136 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ weights_digest()

str encoder_classifier.weights_digest ( Path model_dir)
The SHA-256 of the saved weights, whichever format they were saved in.

Definition at line 1126 of file encoder_classifier.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_result_file()

None encoder_classifier.write_result_file ( Path path,
str model,
str condition,
list[dict[str, object]] rows,
dict[str, object] provenance )
Write one result file the shared scorer can read.

Definition at line 1095 of file encoder_classifier.py.

Here is the caller graph for this function:

Variable Documentation

◆ BUCKET_BATCHES

int encoder_classifier.BUCKET_BATCHES = 50

Definition at line 306 of file encoder_classifier.py.

◆ CONFIDENT_THRESHOLDS

tuple encoder_classifier.CONFIDENT_THRESHOLDS = (0.9, 0.99)

Definition at line 241 of file encoder_classifier.py.

◆ DECISION_CHOICES

tuple encoder_classifier.DECISION_CHOICES = ("argmax", "min-cost")

Definition at line 223 of file encoder_classifier.py.

◆ DEFAULT_ALPHA

float encoder_classifier.DEFAULT_ALPHA = 1.0

Definition at line 213 of file encoder_classifier.py.

◆ DEFAULT_BATCH

int encoder_classifier.DEFAULT_BATCH = 32

Definition at line 250 of file encoder_classifier.py.

◆ DEFAULT_BUDGET_SECONDS

float encoder_classifier.DEFAULT_BUDGET_SECONDS = 3600.0

Definition at line 299 of file encoder_classifier.py.

◆ DEFAULT_CACHE_ROOT

encoder_classifier.DEFAULT_CACHE_ROOT = Path(r"G:\Temp\claude\g--PythonApps-option-c\harness\bench_cache")

Definition at line 283 of file encoder_classifier.py.

◆ DEFAULT_COST_WEIGHT

float encoder_classifier.DEFAULT_COST_WEIGHT = 0.0

Definition at line 218 of file encoder_classifier.py.

◆ DEFAULT_DECISION

str encoder_classifier.DEFAULT_DECISION = "argmax"

Definition at line 224 of file encoder_classifier.py.

◆ DEFAULT_DEVICE

str encoder_classifier.DEFAULT_DEVICE = "auto"

Definition at line 265 of file encoder_classifier.py.

◆ DEFAULT_HF_HOME

encoder_classifier.DEFAULT_HF_HOME = Path(r"G:\Temp\claude\g--PythonApps-option-c\harness\hf_home")

Definition at line 327 of file encoder_classifier.py.

◆ DEFAULT_LEARNING_RATE

int encoder_classifier.DEFAULT_LEARNING_RATE = 3e-5

Definition at line 251 of file encoder_classifier.py.

◆ DEFAULT_MAX_EPOCHS

int encoder_classifier.DEFAULT_MAX_EPOCHS = 4

Definition at line 252 of file encoder_classifier.py.

◆ DEFAULT_MAX_LENGTH

int encoder_classifier.DEFAULT_MAX_LENGTH = 64

Definition at line 249 of file encoder_classifier.py.

◆ DEFAULT_MODEL_ROOT

encoder_classifier.DEFAULT_MODEL_ROOT
Initial value:
1= Path(
2 r"G:\Temp\claude\g--PythonApps-option-c\harness\bench_models"
3)

Definition at line 311 of file encoder_classifier.py.

◆ DEFAULT_SEED

int encoder_classifier.DEFAULT_SEED = 7

Definition at line 245 of file encoder_classifier.py.

◆ DEFAULT_STOP_METRIC

str encoder_classifier.DEFAULT_STOP_METRIC = "ce"

Definition at line 234 of file encoder_classifier.py.

◆ DEFAULT_SUBSET_ROWS

int encoder_classifier.DEFAULT_SUBSET_ROWS = 1000

Definition at line 287 of file encoder_classifier.py.

◆ DEFAULT_SUBSET_SEED

int encoder_classifier.DEFAULT_SUBSET_SEED = 294

Definition at line 288 of file encoder_classifier.py.

◆ DEFAULT_THREADS

int encoder_classifier.DEFAULT_THREADS = 8

Definition at line 258 of file encoder_classifier.py.

◆ DEFAULT_TOKENIZER_DIR

encoder_classifier.DEFAULT_TOKENIZER_DIR
Initial value:
1= Path(
2 # OCT-LINT: disable=no_hardcoded_secrets reason="local HF snapshot path; the entropy is the 40-hex model revision id, not a credential (operator ruling 2026-09-17)"
3 r"G:\Temp\claude\g--PythonApps-option-c\harness\hf_home\hub"
4 r"\models--MoritzLaurer--deberta-v3-base-zeroshot-v2.0\snapshots"
5 r"\8e7e5af5983a0ddb1a5b45a38b129ab69e2258e8"
6)

Definition at line 318 of file encoder_classifier.py.

◆ DEFAULT_VOCAB_RESERVE

int encoder_classifier.DEFAULT_VOCAB_RESERVE = 2000

Definition at line 278 of file encoder_classifier.py.

◆ DEFAULT_WARMUP_SHARE

float encoder_classifier.DEFAULT_WARMUP_SHARE = 0.1

Definition at line 253 of file encoder_classifier.py.

◆ DEVICE_CHOICES

tuple encoder_classifier.DEVICE_CHOICES = ("auto", "cpu", "cuda")

Definition at line 264 of file encoder_classifier.py.

◆ EARLY_STOP_MIN_DELTA

int encoder_classifier.EARLY_STOP_MIN_DELTA = 1e-4

Definition at line 302 of file encoder_classifier.py.

◆ FAST_MAX_LENGTH

int encoder_classifier.FAST_MAX_LENGTH = 48

Definition at line 294 of file encoder_classifier.py.

◆ LABELS

tuple encoder_classifier.LABELS = ("allow", "confirm", "deny")

Definition at line 197 of file encoder_classifier.py.

◆ LISTING_PROGRAMS

frozenset encoder_classifier.LISTING_PROGRAMS = frozenset({"ls", "dir"})

Definition at line 331 of file encoder_classifier.py.

◆ PERMISSIVENESS

tuple encoder_classifier.PERMISSIVENESS = ("deny", "confirm", "allow")

Definition at line 207 of file encoder_classifier.py.

◆ RECURSIVE_OPTION

str encoder_classifier.RECURSIVE_OPTION = "R"

Definition at line 334 of file encoder_classifier.py.

◆ STOP_METRIC_CHOICES

tuple encoder_classifier.STOP_METRIC_CHOICES = ("ce", "cost")

Definition at line 233 of file encoder_classifier.py.

◆ VOCAB_PRUNE_FILE

str encoder_classifier.VOCAB_PRUNE_FILE = "vocab_prune.json"

Definition at line 270 of file encoder_classifier.py.