API reference
Generated from the package docstrings.
Artifacts
recension.artifact
Versioned text artifacts with provenance.
A :class:TextArtifact holds the text being optimized (a prompt, a context
template, a skill file) together with an append-only, linear version history.
Every version after the root carries a :class:Provenance: the diagnosis that
motivated the change, the scores that justified it, the sibling candidates that
were rejected, and a unified diff against the parent. A reviewer can
reconstruct every accepted edit from the artifact alone.
RejectedCandidate
dataclass
A sibling candidate that lost to the accepted version.
Kept in full (text included) so the comparison that justified the accepted edit can be reproduced later.
Source code in recension/artifact.py
26 27 28 29 30 31 32 33 34 35 36 37 | |
Provenance
dataclass
Why a version exists.
Attributes:
| Name | Type | Description |
|---|---|---|
diagnosis |
str
|
Free-text hypothesis about what in the parent text caused the observed failures (or a note such as a rollback reason). |
failure_example_ids |
tuple[str, ...]
|
Ids of the train examples whose failures motivated the change. |
incumbent_score |
float | None
|
Held-out score of the parent version, if measured. |
candidate_score |
float | None
|
Held-out score of this version, if measured. |
rejected_candidates |
tuple[RejectedCandidate, ...]
|
Sibling candidates considered in the same round, with their scores and any leakage flags. |
diff |
str
|
Unified diff against the parent text. Always computed by
:meth: |
Source code in recension/artifact.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
Version
dataclass
One immutable entry in an artifact's history.
Source code in recension/artifact.py
66 67 68 69 70 71 72 73 74 | |
TextArtifact
A text under optimization, with its full version history.
The history is linear and append-only: each version has exactly one
parent, and nothing is ever rewritten or deleted. rollback therefore
appends a new version whose text restores an earlier one, rather than
moving a pointer backwards. The record of having tried and reverted is
itself part of the audit trail.
Source code in recension/artifact.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | |
text
property
text
The current version's text.
__init__
__init__(versions, name='artifact')
Build an artifact from an existing linear history.
Most callers should use :meth:from_text or :meth:from_file.
Raises:
| Type | Description |
|---|---|
ArtifactError
|
If |
Source code in recension/artifact.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
from_text
classmethod
from_text(text, name='artifact')
Create a new artifact whose root version holds text.
Source code in recension/artifact.py
116 117 118 119 120 121 122 123 124 125 | |
from_file
classmethod
from_file(path, name=None)
Create a new artifact from the contents of a text file.
The artifact name defaults to the file's stem.
Source code in recension/artifact.py
127 128 129 130 131 132 133 134 | |
current
current()
The latest version (the incumbent).
Source code in recension/artifact.py
138 139 140 | |
history
history()
All versions, root first, current last.
Source code in recension/artifact.py
147 148 149 | |
get
get(version_id)
Look up a version by id.
Raises:
| Type | Description |
|---|---|
ArtifactError
|
If no version has that id. |
Source code in recension/artifact.py
151 152 153 154 155 156 157 158 159 160 | |
diff
diff(version_a, version_b)
Unified diff between two versions' texts, by version id.
Source code in recension/artifact.py
162 163 164 165 | |
verify
verify()
Check content-addressing integrity of the version history.
Version ids are a hash of (parent_id, text), so editing a version's
text or id after the fact, or breaking the parent chain, is detectable.
Returns a list of human-readable problems, empty when the history is
intact. This is the self-contained tamper-evidence behind
:meth:recension.record.RunRecord.verify.
Source code in recension/artifact.py
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
commit
commit(text, provenance)
Append a new version with text and provenance.
The diff against the parent is computed here and written into the
stored provenance; any caller-supplied provenance.diff is ignored.
Raises:
| Type | Description |
|---|---|
ArtifactError
|
If |
Source code in recension/artifact.py
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
rollback
rollback(version_id)
Restore an earlier version's text by appending a new version.
Raises:
| Type | Description |
|---|---|
ArtifactError
|
If |
Source code in recension/artifact.py
219 220 221 222 223 224 225 226 227 228 229 230 231 | |
to_dict
to_dict()
Plain-dict form, suitable for embedding in a run record.
JSON-pure (lists, not tuples), so a serialize/deserialize round trip is the identity.
Source code in recension/artifact.py
235 236 237 238 239 240 241 242 243 244 | |
from_dict
classmethod
from_dict(data)
Inverse of :meth:to_dict.
Source code in recension/artifact.py
246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
to_json
to_json(*, indent=2)
Serialize the full artifact (history included) to JSON.
Source code in recension/artifact.py
261 262 263 | |
from_json
classmethod
from_json(payload)
Inverse of :meth:to_json.
Source code in recension/artifact.py
265 266 267 268 | |
Evaluation data
recension.evalset
Held-out evaluation data: examples with an explicit train/validation split, and an optional locked test split.
The split is the integrity backbone of the whole library: the optimizer
diagnoses failures on train and accepts candidates only on validation.
An optional test split is never touched during optimization and is scored
exactly once at the end, giving an unbiased estimate that is not subject to the
multiple-comparisons bias of selecting on validation across many rounds.
:class:EvalSet enforces the separation at construction time and fails loud on
anything that would corrupt the acceptance signal.
Example
dataclass
One evaluation example.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Stable identifier; referenced by diagnoses and provenance. |
input |
str
|
The text given to the model (alongside the artifact). |
expected |
str | None
|
Gold output for reference-based objectives, if any. |
rubric |
str | None
|
Per-example grading rubric for model-graded objectives, if any. |
metadata |
dict[str, Any]
|
Any extra fields the objective may need. |
Source code in recension/evalset.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
EvalSet
Examples partitioned into train, validation, and optional test.
Raises:
| Type | Description |
|---|---|
DegenerateEvalError
|
If |
Source code in recension/evalset.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
train
property
train
Examples used to diagnose failures.
validation
property
validation
Held-out examples used to accept or reject candidates.
test
property
test
Locked examples scored once at the end; empty if none were supplied.
from_records
classmethod
from_records(records)
Build an eval set from dict records.
Each record needs id, input, and split ("train",
"validation", or the optional "test"), plus optional
expected and rubric. Unknown keys land in
:attr:Example.metadata.
Raises:
| Type | Description |
|---|---|
DegenerateEvalError
|
On a missing key, an unknown split value, or any split-integrity violation. |
Source code in recension/evalset.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
from_jsonl
classmethod
from_jsonl(path)
Build an eval set from a JSONL file of records (see from_records).
Raises:
| Type | Description |
|---|---|
DegenerateEvalError
|
On a line that is not valid JSON (with the file and line number), or any split-integrity violation. |
Source code in recension/evalset.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
Objectives
recension.objective
Objectives: how a model output is scored against an example.
An :class:Objective maps (model_output, example) to a float, higher is
better, and aggregates per-example scores into one number (mean by default).
Ships :class:ExactMatch, token-level :class:F1, and the model-graded
:class:LLMJudge.
Objective
Bases: Protocol
Protocol every objective implements.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Short identifier recorded in run records. |
model_graded |
bool
|
True when scoring itself calls a model (e.g. a judge). Model-graded acceptance is flagged in the audit record so a reviewer knows the metric is not reference-based. |
Source code in recension/objective.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
score
score(model_output, example)
Score one output against one example; higher is better.
Source code in recension/objective.py
37 38 39 | |
aggregate
aggregate(scores)
Combine per-example scores into a single number.
Source code in recension/objective.py
41 42 43 | |
ExactMatch
1.0 if the output equals the expected value, else 0.0.
Comparison strips surrounding whitespace and, unless case_sensitive,
casefolds both sides.
Source code in recension/objective.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
score
score(model_output, example)
1.0 on a normalized exact match with example.expected, else 0.0.
Source code in recension/objective.py
77 78 79 80 | |
aggregate
aggregate(scores)
Mean of the per-example scores.
Source code in recension/objective.py
82 83 84 | |
F1
Token-level F1 between the output and the expected value.
Tokens are whitespace-separated, casefolded words, the conventional SQuAD-style metric. Returns 1.0 when both sides are empty.
Source code in recension/objective.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
score
score(model_output, example)
Token-level F1 against example.expected.
Source code in recension/objective.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
aggregate
aggregate(scores)
Mean of the per-example scores.
Source code in recension/objective.py
116 117 118 | |
MaxLength
Guard objective: 1.0 if the output is within max_chars, else 0.0.
Intended as a non-regression guard (ReflectiveOptimizer(guards=[...])):
a candidate that starts producing over-long outputs lowers this score and is
rejected even if it improves the primary metric. Reference-free, so no
expected is needed.
Source code in recension/objective.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
score
score(model_output, example)
1.0 if model_output is at most max_chars long, else 0.0.
Source code in recension/objective.py
136 137 138 | |
aggregate
aggregate(scores)
Mean (the fraction of outputs within the limit).
Source code in recension/objective.py
140 141 142 | |
LLMJudge
Model-graded objective: scores outputs against a rubric, 0..1.
Intended as the held-out (validation) judge. Runs flagged as
model_graded in the audit record, and every judge call counts toward
the model-call budget. A per-example rubric overrides the judge-level
one.
Raises:
| Type | Description |
|---|---|
DegenerateEvalError
|
If no rubric is available for an example, or the judge reply contains no parseable number, since a silent default would corrupt the measurement. |
Source code in recension/objective.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | |
score
score(model_output, example)
Ask the judge model for a 0 to 10 grade and normalize it to 0..1.
Source code in recension/objective.py
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | |
aggregate
aggregate(scores)
Mean of the per-example scores.
Source code in recension/objective.py
212 213 214 | |
Budget
recension.budget
The update-time compute dial.
Every knob the optimizer spends model calls on is here, caller-controlled. Nothing about update-time compute is hardcoded in the loop.
Budget
dataclass
Caller-controlled limits on update-time compute.
Attributes:
| Name | Type | Description |
|---|---|---|
candidates_per_round |
int
|
Distinct candidate edits generated per round. |
rounds |
int
|
Maximum optimization rounds. |
diagnosis_depth |
int
|
How many failed train examples are analyzed per round. |
max_model_calls |
int | None
|
Hard ceiling on total model calls for the run
(task scoring, diagnosis, proposals, and judge calls all count).
|
Source code in recension/budget.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
to_dict
to_dict()
Plain-dict form for embedding in a run record.
Source code in recension/budget.py
45 46 47 | |
from_dict
classmethod
from_dict(data)
Inverse of :meth:to_dict.
Source code in recension/budget.py
49 50 51 52 | |
Optimizer
recension.optimizer
The propose/test/accept loop.
:class:ReflectiveOptimizer holds the model fixed and optimizes the text
artifact against held-out evidence: diagnose failures on the train split,
propose distinct candidate edits, score them on the validation split, and
accept only a candidate that beats the incumbent by min_improvement and
survives the leakage checks. Every decision lands in the returned
:class:~recension.record.RunRecord.
ReflectiveOptimizer
Optimizes a :class:TextArtifact against a frozen model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact
|
TextArtifact
|
The text under optimization. Mutated in place: accepted candidates are committed to it with full provenance. |
required |
evalset
|
EvalSet
|
Held-out examples. Failures are diagnosed on |
required |
objective
|
Objective
|
Scoring function; higher is better. |
required |
model
|
Model
|
The frozen model, used for task execution, diagnosis, and proposals. The model is never changed by the optimizer; only the text is. |
required |
budget
|
Budget | None
|
Update-time compute limits. Defaults to |
None
|
seed
|
int | None
|
Optional seed forwarded (derived per call) to the model for
reproducible runs against :class: |
None
|
min_improvement
|
float
|
A candidate must beat the incumbent's validation score by more than this to be accepted. |
1e-06
|
strict_leakage
|
bool
|
When True, a winning candidate that trips a leakage
heuristic raises :class: |
False
|
stop_on_no_improvement
|
bool
|
Stop after the first round whose best candidate fails to beat the incumbent, instead of spending the remaining rounds. |
True
|
overfit_gap
|
float
|
When the eval set has a |
0.1
|
accept_significant
|
bool
|
When True, a candidate is accepted only if its
validation gain is statistically significant (a paired bootstrap
CI on the per-example gain that excludes 0), not merely larger than
|
False
|
alpha
|
float
|
Significance level for the bootstrap CI (default 0.05 = 95%). |
0.05
|
bootstrap_resamples
|
int
|
Resamples for the significance bootstrap. |
2000
|
slice_by
|
str | None
|
An |
None
|
slice_tolerance
|
float
|
A slice is announced as regressed when its score drops by more than this (default 0.0). |
0.0
|
guards
|
Sequence[Objective]
|
Secondary objectives that must not regress. A candidate that
improves the primary objective but lowers any guard's validation
score (beyond |
()
|
guard_tolerance
|
float
|
Allowed drop on a guard before it counts as a regression (default 0.0). |
0.0
|
proposer
|
Proposer | None
|
The candidate generator. Defaults to the built-in
:class: |
None
|
task_max_tokens
|
int
|
|
1024
|
render
|
Renderer | None
|
Maps |
None
|
on_progress
|
ProgressCallback | None
|
Optional callback receiving human-readable progress lines. |
None
|
Raises:
| Type | Description |
|---|---|
BudgetExceeded
|
When |
LeakageDetected
|
In strict mode, when the winning candidate trips a
leakage heuristic. Partial record attached as |
Source code in recension/optimizer.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | |
run
run()
Execute the optimization loop and return the complete audit record.
Source code in recension/optimizer.py
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | |
score_artifact
score_artifact(artifact_text, examples, objective, model, *, render=None, task_max_tokens=1024)
Score one artifact on a set of examples, without running an optimization.
The aggregate objective score of artifact_text over examples against
the frozen model. Used by recension check to compare the current
artifact to a recorded baseline (a prompt regression test).
Source code in recension/optimizer.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
Proposer
recension.proposer
Candidate generation: diagnose failures, propose distinct revisions.
The proposer turns observed failures into a structured hypothesis
(:func:diagnose) and then into genuinely different candidate edits
(:func:propose). Distinctness matters: comparing four rewordings of one idea
tests nothing, so near-duplicate candidates are rejected and regenerated.
FailureCase
dataclass
One failed train example: what went in, what came out, how it scored.
Source code in recension/proposer.py
36 37 38 39 40 41 42 | |
Proposer
Bases: Protocol
Pluggable candidate generator: diagnose failures, then propose edits.
The built-in heuristic proposer (:class:DefaultProposer) is one
implementation. A custom proposer, for example one wrapping an external
optimizer such as DSPy or GEPA, can be injected with
ReflectiveOptimizer(proposer=...) without changing the artifact,
evalset, or record abstractions: recension keeps owning versioning,
held-out measurement, leakage detection, and the audit record; the proposer
only supplies the candidate edits. This is the seam that lets recension act
as the measurement-and-governance layer on top of any optimizer.
Source code in recension/proposer.py
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
diagnose
diagnose(model, artifact_text, failures, *, seed=None)
Return a short hypothesis about why artifact_text failed.
Source code in recension/proposer.py
211 212 213 214 215 216 217 218 219 220 | |
propose
propose(model, artifact_text, diagnosis, n, *, seed=None)
Return up to n distinct candidate revisions of artifact_text.
Source code in recension/proposer.py
222 223 224 225 226 227 228 229 230 231 232 | |
DefaultProposer
The built-in proposer: the module-level :func:diagnose/:func:propose.
Source code in recension/proposer.py
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | |
CallableProposer
Adapt plain functions into a :class:Proposer.
Wrap an external optimizer's propose function (and optionally a diagnose
function) without writing a class. Either may be None for diagnose, in
which case the built-in diagnosis is used. The seam for "bring your own
optimizer": recension governs the run; your function proposes the edits.
Source code in recension/proposer.py
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
diagnose
diagnose(model, artifact_text, failures, *, max_tokens=1024, seed=None)
Ask the model why the artifact produced these failures.
Returns the model's hypothesis as free text (recorded verbatim in the round record).
Source code in recension/proposer.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | |
propose
propose(model, artifact_text, diagnosis, n, *, max_tokens=4096, seed=None)
Generate up to n distinct candidate revisions of the artifact.
Near-duplicates (of the incumbent or of each other, by
difflib.SequenceMatcher ratio) are rejected and regenerated, up to
ATTEMPTS_PER_CANDIDATE attempts per requested candidate. If the model
cannot produce n distinct candidates within that allowance, the
distinct subset found so far is returned; the optimizer records how many
candidates each round actually compared, so a shortfall is visible in the
audit record rather than silently padded.
Source code in recension/proposer.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
extract_candidate
extract_candidate(reply)
Pull the revised artifact out of a proposal reply.
Prefers the <revised_artifact> tags the prompt asks for; falls back to
the whole reply (stripped) when a model ignores the tagging instruction.
Source code in recension/proposer.py
169 170 171 172 173 174 175 176 177 178 | |
Leakage heuristics
recension.leakage
Leakage and overfitting heuristics for candidate artifacts.
These checks are heuristics, not proofs. They catch the two cheapest ways an edit can game a held-out score:
- Verbatim validation spans: the candidate text embeds a long span copied from a validation example (its input, expected output, or rubric). That is memorization of the held-out set, not generalization.
- Implausible gain: the candidate's validation gain is large while its train gain is flat or negative. Honest improvements usually move both; a validation-only jump suggests the edit exploits validation-specific cues.
A tripped heuristic produces a :class:LeakageFlag. By default flags are
surfaced in the run record, not silently enforced; the optimizer's strict
mode turns them into :class:~recension.exceptions.LeakageDetected.
LeakageFlag
dataclass
One tripped heuristic, with enough detail to review it.
Source code in recension/leakage.py
36 37 38 39 40 41 42 43 44 | |
check_candidate
check_candidate(candidate_text, incumbent_text, evalset, *, train_gain=None, validation_gain=None, min_span_length=DEFAULT_MIN_SPAN_LENGTH, min_validation_gain=DEFAULT_MIN_VALIDATION_GAIN, gain_ratio=DEFAULT_GAIN_RATIO)
Run all leakage heuristics against one candidate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidate_text
|
str
|
The proposed artifact text. |
required |
incumbent_text
|
str
|
The current artifact text. Spans already present in the incumbent are not re-flagged, only newly introduced validation content counts. |
required |
evalset
|
EvalSet
|
Source of the validation examples to scan for. |
required |
train_gain
|
float | None
|
Candidate train score minus incumbent train score, if measured. Both gains are required for the implausible-gain check. |
None
|
validation_gain
|
float | None
|
Candidate validation score minus incumbent validation score, if measured. |
None
|
min_span_length
|
int
|
Shortest copied span (characters) considered leakage. |
DEFAULT_MIN_SPAN_LENGTH
|
min_validation_gain
|
float
|
Validation gain below which the implausible-gain heuristic never fires (small gains are noise, not leakage). |
DEFAULT_MIN_VALIDATION_GAIN
|
gain_ratio
|
float
|
Fire when |
DEFAULT_GAIN_RATIO
|
Returns:
| Type | Description |
|---|---|
list[LeakageFlag]
|
All tripped flags, empty if the candidate looks clean. |
Source code in recension/leakage.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
Statistics
recension.stats
Seeded bootstrap statistics for honest acceptance decisions.
The optimizer can require an accepted candidate's validation gain to be
statistically significant, not merely larger than an epsilon, so a candidate
that wins by noise is rejected. This module provides the paired-difference
bootstrap that backs that gate. It is pure stdlib (random.Random) and fully
deterministic given a seed, so a seeded run against MockModel stays
reproducible.
BootstrapResult
dataclass
A paired-difference bootstrap of two aligned per-example score vectors.
Attributes:
| Name | Type | Description |
|---|---|---|
mean_difference |
float
|
Mean of |
ci_low |
float
|
Lower bound of the |
ci_high |
float
|
Upper bound of that interval. |
alpha |
float
|
The significance level used (e.g. |
n_resamples |
int
|
Number of bootstrap resamples drawn. |
Source code in recension/stats.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
significant
property
significant
True when the interval excludes 0, i.e. the gain is significantly positive.
paired_bootstrap
paired_bootstrap(incumbent, candidate, *, alpha=0.05, n_resamples=2000, seed=None)
Bootstrap a confidence interval on the mean paired score difference.
Resamples the per-example differences candidate_i - incumbent_i with
replacement to estimate a percentile confidence interval on their mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
incumbent
|
Sequence[float]
|
Per-example validation scores of the incumbent. |
required |
candidate
|
Sequence[float]
|
Per-example validation scores of the candidate, aligned with
|
required |
alpha
|
float
|
Significance level; the interval is |
0.05
|
n_resamples
|
int
|
Number of resamples. |
2000
|
seed
|
int | None
|
Seed for the resampling RNG; pass one for reproducibility. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the vectors differ in length or are empty. |
Source code in recension/stats.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | |
Run records
recension.record
The audit record: a complete, serializable history of an optimization run.
A :class:RunRecord must be complete enough that a reviewer who did not run
the optimization can reconstruct every decision: the baseline, every round's
diagnosis, every candidate (accepted and rejected) with its scores and leakage
flags, the diffs, the model-call counts, and why the run stopped. The full
artifact (with version history) is embedded so the record stands alone.
GuardScore
dataclass
A guard objective's incumbent-vs-candidate score for the best candidate.
Recorded when the optimizer runs with guards=[...], so a reviewer sees
why a candidate was held back (or that it cleared the guards).
Source code in recension/record.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
regressed
property
regressed
True when the candidate scores worse than the incumbent on this guard.
SliceScore
dataclass
Baseline vs final score for one subgroup of the validation set.
Recorded per distinct value of the optimizer's slice_by metadata key, so
a run that improves overall but regresses a segment is visible rather than
averaged away.
Source code in recension/record.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | |
regressed
property
regressed
True when this slice scored worse at the end than at the start.
SignificanceRecord
dataclass
The significance test applied to a candidate's validation gain.
Recorded for the best candidate of a round when the optimizer runs with
accept_significant=True, so a reviewer can see not just the score delta
but whether it cleared the confidence bar.
Attributes:
| Name | Type | Description |
|---|---|---|
mean_difference |
float
|
Mean per-example validation gain over the incumbent. |
ci_low |
float
|
Lower bound of the bootstrap confidence interval on the gain. |
ci_high |
float
|
Upper bound of that interval. |
alpha |
float
|
Significance level (the interval is |
significant |
bool
|
True when the interval excludes 0 (gain significantly > 0). |
Source code in recension/record.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
CandidateRecord
dataclass
One candidate edit considered in a round.
Attributes:
| Name | Type | Description |
|---|---|---|
candidate_id |
str
|
Stable id within the run (e.g. |
text |
str
|
The full candidate artifact text. |
validation_score |
float | None
|
Aggregate held-out score, or |
diff |
str
|
Unified diff against the incumbent at proposal time. |
leakage_flags |
tuple[str, ...]
|
Human-readable descriptions of tripped heuristics. |
accepted |
bool
|
Whether this candidate became the new incumbent. |
train_score |
float | None
|
Aggregate train score of this candidate, populated only
for the accepted candidate (the only one re-scored on train, to
check the implausible-gain heuristic). |
significance |
SignificanceRecord | None
|
The significance test on this candidate's validation
gain, populated for the round's best candidate when the run used
|
Source code in recension/record.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
RoundRecord
dataclass
Everything that happened in one optimization round.
Source code in recension/record.py
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
RunRecord
dataclass
Complete, serializable history of one ReflectiveOptimizer.run().
Attributes:
| Name | Type | Description |
|---|---|---|
artifact |
dict[str, Any]
|
Full snapshot ( |
objective_name |
str
|
The objective used for all scoring. |
model_graded |
bool
|
True if the objective itself calls a model
(:class: |
seed |
int | None
|
The seed the optimizer was constructed with, if any. |
budget |
dict[str, Any]
|
|
baseline_version_id |
str
|
Incumbent version at the start of the run. |
baseline_score |
float
|
Held-out validation score of the baseline. |
rounds |
list[RoundRecord]
|
One :class: |
final_version_id |
str
|
Incumbent version at the end of the run. |
final_score |
float
|
Held-out validation score of the final incumbent. |
final_test_score |
float | None
|
Score of the final incumbent on the locked test
split, computed exactly once; |
test_validation_gap |
float | None
|
|
validation_overfit |
bool
|
True when |
total_input_tokens |
int
|
Total input tokens reported by the model across the run (0 if the model does not report usage). |
total_output_tokens |
int
|
Total output tokens reported across the run. |
total_model_calls |
int
|
All model calls spent, including judge calls. |
stopped_reason |
str
|
Why the run ended ( |
started_at |
str
|
ISO 8601 timestamp. |
finished_at |
str
|
ISO 8601 timestamp. |
Source code in recension/record.py
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
to_dict
to_dict()
Plain-dict form of the whole record.
Source code in recension/record.py
226 227 228 229 | |
from_dict
classmethod
from_dict(data)
Inverse of :meth:to_dict.
Source code in recension/record.py
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | |
to_json
to_json(*, indent=2)
Serialize to JSON (valid even for partial records with uncomputed scores).
Source code in recension/record.py
302 303 304 | |
from_json
classmethod
from_json(payload)
Inverse of :meth:to_json.
Source code in recension/record.py
306 307 308 309 | |
save
save(path)
Write the record to a JSON file.
Source code in recension/record.py
311 312 313 | |
load
classmethod
load(path)
Read a record from a JSON file.
Source code in recension/record.py
315 316 317 318 | |
restored_artifact
restored_artifact()
Rehydrate the embedded artifact (for diffs and inspection).
Source code in recension/record.py
322 323 324 | |
fingerprint
fingerprint()
Deterministic SHA-256 over the canonical record JSON.
Two records with identical content produce the same fingerprint. Store
it (or a signature of it) somewhere trusted to detect later tampering
with any field; the artifact lineage is additionally self-verifiable
via :meth:verify.
Source code in recension/record.py
328 329 330 331 332 333 334 335 336 337 | |
verify
verify()
Integrity problems with the embedded artifact's version chain.
Empty when intact. Because version ids are content-addressed, this
catches tampering with a version's text or id without needing any
external reference. (Tampering with non-versioned fields such as a
recorded score is caught instead by comparing :meth:fingerprint or a
signature against a trusted copy.)
Source code in recension/record.py
339 340 341 342 343 344 345 346 347 348 | |
sign
sign(key)
HMAC-SHA256 of the fingerprint with key (hex), for signed records.
Source code in recension/record.py
350 351 352 353 354 355 | |
verify_signature
verify_signature(key, signature)
Constant-time check that signature matches :meth:sign for key.
Source code in recension/record.py
357 358 359 | |
summary
summary()
Human-readable account of the run: baseline, rounds, diffs, scores.
Source code in recension/record.py
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
HTML report
recension.report
A self-contained HTML audit report rendered from a :class:RunRecord.
render_report turns the full audit record into a single standalone HTML page
(inline CSS, no assets, no network) that a reviewer can open, share, or attach
to a change request. It surfaces everything the record carries: the baseline and
final scores, the locked test estimate and overfit flag, every round's diagnosis
and candidates (with significance, guard, and leakage detail), the accepted diff,
the per-slice breakdown, the token ledger, and the record's integrity status.
render_report
render_report(record)
Render record as a complete, standalone HTML document (a string).
Source code in recension/report.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
Models
recension.models.base
The minimal model interface every backend implements.
The optimizer core is provider-agnostic: it talks to anything satisfying the
:class:Model protocol. Backends ship for Anthropic (optional extra) and a
deterministic mock for offline tests.
Role
module-attribute
Role = Literal['system', 'user', 'assistant']
Message roles understood by every backend.
Message
Bases: TypedDict
One chat message: a role and its text content.
Source code in recension/models/base.py
19 20 21 22 23 | |
TokenUsage
dataclass
Input/output token counts for one completion (or a sum of them).
Source code in recension/models/base.py
26 27 28 29 30 31 32 33 34 35 36 37 | |
SupportsUsage
Bases: Protocol
Optional capability: a model that reports the token usage of its last call.
Models that implement it feed the optimizer's cost ledger; models that do not simply contribute zeros, so usage reporting is fully backward compatible.
Source code in recension/models/base.py
40 41 42 43 44 45 46 47 48 49 50 51 52 | |
last_usage
property
last_usage
Token usage of the most recent complete call.
Model
Bases: Protocol
Narrow protocol for a chat-completion model.
Implementations must count every completion in :attr:call_count; the
optimizer uses it to enforce Budget.max_model_calls.
Source code in recension/models/base.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | |
call_count
property
call_count
Number of complete calls made so far on this instance.
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Return the model's text completion for messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
Conversation so far; at most one |
required |
max_tokens
|
int
|
Upper bound on generated tokens. |
1024
|
temperature
|
float
|
Sampling temperature; 0 for greedy. |
0.0
|
seed
|
int | None
|
Optional determinism hint. Backends that cannot honor it (e.g. hosted APIs) document that they ignore it. |
None
|
Source code in recension/models/base.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | |
recension.models.mock
Deterministic mock model for offline tests and reproducible examples.
The entire test suite runs against :class:MockModel: no network, no API
key. Given the same messages, seed, and script, it always returns the same
output, which is what makes seeded optimizer runs reproducible.
MockModel
A deterministic, scriptable stand-in for a real model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
script
|
Callable[[list[Message]], str] | None
|
Optional callable mapping the message list to a reply. Use it to simulate task answers, diagnoses, judges, or candidate proposals in tests and examples. When omitted, replies are deterministic pseudo-text derived from a hash of the messages and seed. |
None
|
seed
|
int
|
Folded into the unscripted reply hash, so different seeds give different (but stable) outputs. |
0
|
Source code in recension/models/mock.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
call_count
property
call_count
Number of complete calls made on this instance.
last_usage
property
last_usage
Synthetic, deterministic token usage of the last call (roughly chars/4).
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Return a deterministic reply for messages.
The seed argument, when given, overrides the instance seed for
this call. max_tokens and temperature are accepted for
protocol compatibility; they do not change the output.
Source code in recension/models/mock.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
recension.models.anthropic
Anthropic backend for the :class:~recension.models.base.Model protocol.
Requires the optional extra: pip install "recension[anthropic]". The API
key is read from the environment (ANTHROPIC_API_KEY) by the Anthropic SDK
itself; this class never accepts a key argument, so a key cannot end up in
code or config.
AnthropicModel
Model backend that calls the Anthropic Messages API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Anthropic model id. Defaults to |
DEFAULT_MODEL
|
max_retries
|
int
|
Passed through to the SDK client. |
2
|
send_temperature
|
bool | None
|
Whether to send the |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If the |
Note
The seed parameter of :meth:complete is ignored, since the Anthropic
API does not support sampling seeds. Determinism in tests comes from
:class:~recension.models.mock.MockModel, never from this backend.
Source code in recension/models/anthropic.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
call_count
property
call_count
Number of complete calls made on this instance.
last_usage
property
last_usage
Token usage of the last call, read from the API response.
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Send messages to the Anthropic API and return the reply text.
system messages are lifted into the API's system parameter;
user/assistant messages pass through in order.
Source code in recension/models/anthropic.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
should_send_temperature
should_send_temperature(model, override)
Decide whether to send temperature for model.
override wins when set; otherwise infer from the known no-sampling model
prefixes. Pure and SDK-free so the decision is testable offline.
Source code in recension/models/anthropic.py
112 113 114 115 116 117 118 119 120 | |
split_system
split_system(messages)
Split a message list into (system text, chat messages).
Multiple system messages are joined with blank lines. Exposed as a
module function so the conversion is testable without the SDK installed.
Source code in recension/models/anthropic.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
recension.models.openai
OpenAI backend for the :class:~recension.models.base.Model protocol.
Requires the optional extra: pip install "recension[openai]". The API key is
read from the environment (OPENAI_API_KEY) by the OpenAI SDK itself; this
class never accepts a key argument, so a key cannot end up in code or config.
Because it speaks the standard Chat Completions API, this backend also drives
OpenAI-compatible servers (vLLM, LM Studio, OpenRouter, Together, and others)
by passing their base_url.
OpenAIModel
Model backend that calls the OpenAI Chat Completions API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
OpenAI model id. Defaults to |
DEFAULT_MODEL
|
base_url
|
str | None
|
Optional base URL for an OpenAI-compatible server. |
None
|
max_retries
|
int
|
Passed through to the SDK client. |
2
|
send_temperature
|
bool | None
|
Whether to send |
None
|
client
|
Any
|
A pre-built OpenAI client to use instead of constructing one
(for advanced configs such as Azure, or for testing). When given,
the |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If the |
Note
seed is forwarded to the API as a best-effort determinism hint; the
OpenAI API does not guarantee reproducibility. Deterministic tests use
:class:~recension.models.mock.MockModel, never this backend.
Source code in recension/models/openai.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
call_count
property
call_count
Number of complete calls made on this instance.
last_usage
property
last_usage
Token usage of the last call, read from the API response.
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Send messages to the Chat Completions API and return the reply text.
Source code in recension/models/openai.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
is_reasoning_model
is_reasoning_model(model)
True for OpenAI reasoning models (o-series, gpt-5). Pure; testable offline.
Source code in recension/models/openai.py
120 121 122 | |
should_send_temperature
should_send_temperature(model, override)
Decide whether to send temperature for model.
override wins when set; otherwise infer from the reasoning-model
prefixes. Pure and SDK-free so the decision is testable offline.
Source code in recension/models/openai.py
125 126 127 128 129 130 131 132 133 | |
usage_from_response
usage_from_response(response)
Read token usage from a Chat Completions response (SDK-free; testable).
Source code in recension/models/openai.py
144 145 146 147 148 149 150 | |
recension.models.gemini
Google Gemini backend for the :class:~recension.models.base.Model protocol.
Requires the optional extra: pip install "recension[gemini]". The API key is
read from the environment (GEMINI_API_KEY or GOOGLE_API_KEY) by the
google-genai SDK itself; this class never accepts a key argument, so a key
cannot end up in code or config.
GeminiModel
Model backend that calls the Google Gemini API (google-genai SDK).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Gemini model id. Defaults to |
DEFAULT_MODEL
|
client
|
Any
|
A pre-built |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If the |
Note
seed is forwarded as a best-effort determinism hint; the API does not
guarantee reproducibility. Deterministic tests use
:class:~recension.models.mock.MockModel, never this backend.
Source code in recension/models/gemini.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
call_count
property
call_count
Number of complete calls made on this instance.
last_usage
property
last_usage
Token usage of the last call, read from the API response.
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Send messages to the Gemini API and return the reply text.
system messages become the system_instruction; assistant
messages are mapped to Gemini's model role.
Source code in recension/models/gemini.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
to_gemini_contents
to_gemini_contents(messages)
Split messages into (system instruction, Gemini contents).
system messages are joined into the instruction; user stays user
and assistant becomes model. Pure and SDK-free so the mapping is
testable offline.
Source code in recension/models/gemini.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
usage_from_response
usage_from_response(response)
Read token usage from a Gemini response (SDK-free; testable).
Source code in recension/models/gemini.py
116 117 118 119 120 121 122 | |
recension.models.ollama
Ollama backend for the :class:~recension.models.base.Model protocol.
Runs local models served by Ollama <https://ollama.com>_. Needs no extra
dependency: it talks to the local HTTP API with the standard library. Point it
at a running Ollama server (default http://localhost:11434) and pull the
model first (ollama pull llama3.2).
OllamaModel
Model backend that calls a local Ollama server's chat API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Ollama model name (must be pulled locally). Defaults to
|
DEFAULT_MODEL
|
host
|
str
|
Base URL of the Ollama server. |
'http://localhost:11434'
|
timeout
|
float
|
Per-request timeout in seconds. |
120.0
|
transport
|
Transport | None
|
Override the HTTP transport |
None
|
Note
seed is forwarded to Ollama; local models honor it fairly well, but
deterministic tests still use :class:~recension.models.mock.MockModel,
never a live server.
Source code in recension/models/ollama.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
call_count
property
call_count
Number of complete calls made on this instance.
last_usage
property
last_usage
Token usage of the last call, read from the Ollama response.
complete
complete(messages, *, max_tokens=1024, temperature=0.0, seed=None)
Send messages to the Ollama chat API and return the reply text.
Source code in recension/models/ollama.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
build_payload
build_payload(model, messages, max_tokens, temperature, seed)
Build the Ollama /api/chat request body (pure; testable).
Source code in recension/models/ollama.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
usage_from_response
usage_from_response(data)
Read token usage from an Ollama response (pure; testable).
Source code in recension/models/ollama.py
103 104 105 106 107 108 | |
Exceptions
recension.exceptions
Exception types for recension.
All library-specific errors derive from :class:RecensionError so callers can
catch the whole family with one clause. Measurement-integrity problems get
their own loud types; they are never swallowed.
RecensionError
Bases: Exception
Base class for all recension errors.
Source code in recension/exceptions.py
25 26 | |
ArtifactError
Bases: RecensionError
Raised for invalid artifact operations (unknown version, no-op commit).
Source code in recension/exceptions.py
29 30 | |
BudgetExceeded
Bases: RecensionError
Raised when an optimization run hits Budget.max_model_calls.
When raised by ReflectiveOptimizer.run(), :attr:record carries the
partial run record up to the point of the overrun, so the audit trail is
not lost with the failure.
Source code in recension/exceptions.py
33 34 35 36 37 38 39 40 41 42 43 | |
DegenerateEvalError
Bases: RecensionError
Raised when an eval set cannot produce an honest signal.
Examples: an empty train or validation split, or an example id that appears in both splits (which would contaminate the acceptance signal).
Source code in recension/exceptions.py
46 47 48 49 50 51 | |
LeakageDetected
Bases: RecensionError
Raised in strict mode when a winning candidate trips a leakage heuristic.
Outside strict mode the same condition is recorded as a flag on the
candidate instead of raising. See :mod:recension.leakage. When raised by
ReflectiveOptimizer.run(), :attr:record carries the partial run
record so the audit trail survives the failure.
Source code in recension/exceptions.py
54 55 56 57 58 59 60 61 62 63 64 65 | |
ConfigError
Bases: RecensionError
Raised for invalid or incomplete CLI/run configuration.
Source code in recension/exceptions.py
68 69 | |
CLI
recension.cli
The recension command-line interface.
A thin wrapper over the library; no logic lives only here. Three commands:
recension run --config run.yamlexecutes an optimization and writes the run record (and optionally the optimized artifact text) to disk.recension show record.jsonprints a human-readable summary of a record.recension diff record.json vA vBprints the diff between two artifact versions stored in a record.
Exit codes: 0 success; 1 configuration or usage error; 2 measurement-integrity failure (budget exceeded or leakage in strict mode, where the partial record is still written so the audit trail survives).
main
main(argv=None)
Entry point for the recension console script.
Source code in recension/cli.py
42 43 44 45 46 47 48 49 50 51 52 53 54 | |