Hold a whole repository in one model context, by asking a compressor what your task does not need.
Built with Paritok — the compression model this project uses as a relevance oracle.
Post a segment of source to Paritok's hosted /compress endpoint together with a
query. If the model judges the segment irrelevant to that query, it answers
HTTP 200 with an empty body.
Every implementation we have read treats that empty body as an error and falls
back to sending the original. Paritok's own shipped GpuServerStrategy.compress()
returns str, and returns the caller's own content on 401, on 403, on any
exception, on gpu_available: false, and on a non-string body. There is no status
channel, so "irrelevant" and "the backend died" are the same value.
Read the other way, an empty body is not a failure. It is a verdict worth zero tokens.
| response | the common reading | Resident's reading |
|---|---|---|
| empty body, provably complete | "nothing to compress" → send original | Drop — 0 tokens |
| non-empty body | keep | Keep(body, ref_id) |
| body identical to input | keep | Degraded(passthrough) |
unbalanced [SEG introduced |
keep | Degraded(malformed) |
That distinction is the entire project. A compressor returning
Everything else in this codebase exists to make that difference measurable and safe, which turned out to be about 95% of the work.
uv tool install git+https://github.com/NithishaVenkatesh/Paritok # recommended
pipx install git+https://github.com/NithishaVenkatesh/Paritok # or
git clone https://github.com/NithishaVenkatesh/Paritok && cd Paritok && pip install -e .Python 3.11+. A free Paritok key comes from paritok.com.
The base install is 18 MB. To reproduce the published fidelity figures
exactly, add the eval extra:
pip install -e ".[eval]"That extra pulls paritok-audit, the extractor every published fidelity number
was measured with — and, transitively, paritok[proxy] → sentence-transformers
→ torch, which takes the environment from 18 MB to 767 MB. None of it is ever
imported: paritok_audit.atoms was traced at runtime and reaches only ast, re
and dataclasses. Without the extra the ledger falls back to core/facts_alt.py,
the independently written extractor, and every context pack states in its header
which one built it.
resident initinit takes the key, then proves the backend is actually filtering before you
trust a single number from it — see doctor for why that is
not a formality. Only a key the canary has just validated is written to disk
(~/.config/resident/key, mode 0600); resident init --forget removes it, and
PARITOK_API_KEY in the environment always wins over the stored copy.
Shell completion, if you want it: resident --install-completion.
Resident is not tied to any one agent. scan --out writes a context pack: the
whole repository, admitted under your intent, as one file you hand to Claude Code,
Cursor, Copilot, an SDK loop, or a chat window.
resident scan . -i "where do we retry a failed operation after waiting?" -o residency.mdscan prints a verdict breakdown and the residency total, then writes the pack.
Measured figures for one source under exactly that intent — joblib 1.5.3, cloned
at its tag, from the corpus B run (eval/FULLRUN_RESULTS_B2.json):
| segments | tokens | |
|---|---|---|
| source | 281 | 216,123 |
| dropped to zero | 29 | 0 |
| compressed | 181 | — |
| verbatim (below the compressor's floor) | 71 | — |
| residency | 78,597 — 63.6% reduction | |
| residency with the fact ledger on (the default) | 104,906 — 51.5% reduction |
The default carries the ledger, which trades ~12 points of reduction for atom
retention of 97% against an independent extractor. --no-facts gives the first row.
Then, in whatever agent you use:
Read
residency.mdand enumerate every site that retries after a delay.
The pack self-describes. Its header tells the reading model what a [REF:...]
entry is, what a tombstone means, and — critically — that an absent segment is a
recorded decision, not an oversight. That is the one thing a downstream model
cannot infer from the bodies alone.
Only resident ask needs an ANTHROPIC_API_KEY. Everything
above needs PARITOK_API_KEY alone.
flowchart TB
A["working tree"] --> B["segment.py — AST boundaries, 512 ≤ t ≤ 3000 tokens"]
B --> C{"store.py — cache hit?"}
C -- "miss" --> D["adapters/paritok.py — POST /compress with query"]
D --> E["verdict.py — parse exactly once into Drop / Keep / Degraded"]
C -- "hit" --> F
E --> F["scan.py — assemble · facts.py — restore lost atoms"]
F --> H{"fits the budget?"}
H -- "yes" --> I["context pack via --out · agent.py ask + pager"]
H -- "no" --> J["REFUSE, exit 4 — never truncate"]
style E fill:#8A2BE2,color:#fff
style J fill:#c0392b,color:#fff
core/verdict.py is 79 lines and the highest-risk file in the system, because four
very different events all arrive as a string:
"" a genuine DROP
"" a torn connection, truncated mid-body
<the original content> the backend is down and passed content through
<half a [SEG] block> the reply was truncated by num_predict
Collapsing those into str | None is exactly how you publish a 97% saving on a run
where the compressor never executed. So the boundary parses once, into a closed
set:
stateDiagram-v2
[*] --> HTTP_200
HTTP_200 --> EmptyBody: body is empty
HTTP_200 --> NonEmptyBody: body is not empty
EmptyBody --> Drop: completeness signal present
EmptyBody --> Degraded_truncated: no completeness signal
NonEmptyBody --> Degraded_passthrough: body equals input
NonEmptyBody --> Degraded_malformed: SEG imbalance introduced
NonEmptyBody --> Keep: otherwise
Drop --> [*]: 0 tokens
Keep --> [*]: compressed body plus ref_id
Degraded_truncated --> [*]: coverage hole, exit 3
Degraded_passthrough --> [*]: coverage hole, exit 3
Degraded_malformed --> [*]: coverage hole, exit 3
Two rules in the adapter follow from this and are not optional:
- An empty body alone is never sufficient for a
Drop. It must carry a positive completeness signal —Content-Length: 0, or a cleanly terminated chunked stream. This makes a transport failure structurally incapable of manufacturing a drop. Without it, some fraction of any measured false-drop rate is a network fault wearing a verdict's clothes. - Never call
_unwrap_seg. Paritok'slocal_model._unwrap_segreturns the whole stripped reply when the[SEG]…[/SEG]wrapper is unbalanced — which is precisely what anum_predict-truncated generation looks like. Routed through it, a truncated reply becomes a plausible non-empty body.
is_usable() gates every savings calculation, and a run containing any Degraded
verdict exits 3 and reports no saving at all.
The adapter subclasses GpuServerStrategy and overrides exactly one method, so
__init__, check(), _base() and GpuServerConfig are all inherited. The
subclass is simultaneously the fix and the bug report.
core/segment.py splits on ast boundaries with a line-window fallback, bounded by
- The floor is Paritok's own
min_tokensgate (config.py:54). Sub-floor content comes back uncompressed and would read as aKeep. - The ceiling is the shipped runtime's
CHUNK_SIZE = 3000, even though the training and benchmark value in the same file is 2000 and a docstring warns that beyond ~2000 tokens the model leaves its trained distribution. That warning was treated as a hypothesis to measure, not a fact to obey: at$N \approx 302$ segments and 9–20s per keep, halving segment size costs 57% more calls on a throughput-bound system. Gate A5 measured verdict stability at both and the cap stayed at 3000.
Ordering is deterministic and independent of completion order — otherwise concurrency
reorders the prompt prefix and every upstream cache hit vanishes. Small files batch
only within a package, never across intent-named paths. Symlink containment is an
explicit check, not a reliance on CPython rglob behaviour.
core/store.py is content-addressed, and the key carries everything that affects the
output:
Paritok's own cache is keyed on content alone (compress.py:210), so the same
bytes return the same compression regardless of the intent they were compressed for
— quietly defeating the strongest lever the model has. Two further rules were each
learned from a specific failure:
Dropis a stored value, never key absence. An empty body is falsy, so the naturalif result: cache.set(...)persists no drops at all — and drops are the majority case. Negative TTL equals positive TTL.- Never consult a path→id map. Paritok's does substring matching
(
compress.py:186-188), so deleting a trailing function makes the new file a substring of the old one and it serves the pre-edit compression. Reproduced, not inferred.
TTL is 7 days with ±10% jitter, because 300 keys written in one scan with identical TTLs all expire within the same few minutes and turn the next run into a fully cold hour.
flowchart TB
V{"verdict"} --> K["Keep"]
V --> D["Drop"]
V --> G["Degraded"]
K --> KF{"atoms lost<br/>vs original?"}
KF -- yes --> KL["body + '# facts:' line<br/>(literal substrings)"]
KF -- no --> KB["body"]
D --> DA{"segment<br/>carries atoms?"}
DA -- yes --> DT["'# dropped, facts:' tombstone<br/>+ ref id → reversible"]
DA -- no --> DZ["nothing<br/>true 0-token drop"]
G --> GH["declared coverage hole<br/>never treated as a drop"]
style DZ fill:#27ae60,color:#fff
style GH fill:#c0392b,color:#fff
core/scan.py runs bounded concurrency with a polite AIMD ramp, granular
connect/read/total timeouts, exponential backoff with full jitter, and capped
attempts. Every verdict is written to the store as it lands, so Ctrl-C costs at
most the in-flight batch.
If the assembled residency does not fit the budget, it refuses rather than truncates — a truncated residency is top-$k$ retrieval wearing a coverage claim.
Corpus B produced the number that changed the design. Across 2,150,959 tokens the corpus holds 86,877 critical atoms by the scorer's extractor and 87,516 by the independent one (paths, identifiers, error classes, numbers, commands, URLs, hashes), and
while losing one atom costs a full fidelity point. Atoms are cheap in tokens and expensive in fidelity. The fact-gated family of strategies gets the contract right — exact facts must survive verbatim — but the usual remedy is wrong by an order of magnitude: when facts die it restores the entire original segment, which is why that arm sits at ~27% reduction.
core/facts.py restores only the missing facts. Both the # facts: line and the
# dropped, facts: tombstone are literal substrings of the source, so retention
stays decidable by exact search.
Measured effect: independent-extractor fidelity 54% → 97% for about 8 points of reduction. The ref pointer that makes tombstones reversible costs 0.09 points (52.28% → 52.19%) — a cheap price for a whole-segment recovery path.
core/agent.py never uses Paritok's expand_context virtual tool. Measured against
the proxy: it answers an expansion by re-POSTing the whole thread with the original
attached, so for compression ratio
— worse than never compressing. That loss lives in the gateway's control flow, not in compression, so owning the paging avoids it by construction.
sequenceDiagram
participant M as model
participant P as Pager
participant R as residency (byte-stable prefix)
M->>R: turn 1, reads compressed entries
M->>P: expand a ref id
P->>P: pin the original at turn 1
P-->>M: appended at the END, prefix untouched
Note over R,P: prefix stays byte-stable,<br/>so upstream caching still hits
M->>M: turns 2 to 8
P->>P: evict at turn 9, unpin_after = 8
Note over P: the pager IS a pinning mechanism.<br/>Without eviction the residency<br/>inflates monotonically.
Residency content is treated as untrusted: Paritok's rules preserve error strings verbatim, so text placed in a source file reaches the model. The residency is wrapped in a nonce-delimited envelope, the system prompt marks it as data, and the tool surface is read-only — no shell, no writes.
core/ledger.py is an append-only log; eval/recompute.py regenerates every
published number from it. Nothing in the reports is typed by hand. The evaluation
protocol was committed before any arm ran, with pre-registered falsification
thresholds.
One accounting rule earns its own note. Anthropic splits prompt tokens across three fields:
prompt = input_tokens + cache_creation_input_tokens + cache_read_input_tokens
A system whose whole design is a large stable cached prefix would omit almost all of
its own cost by reading only input_tokens — producing a spectacular and completely
false saving, in the flattering direction.
First-run setup. Takes a key, issues the canary probe, and refuses to continue unless the backend genuinely drops it.
| flag | default | meaning |
|---|---|---|
--save/--no-save |
save | store the validated key at ~/.config/resident/key, mode 0600 |
--forget |
— | delete the stored key and exit |
The key is written only after the canary passes, so a bad key is never left on
disk for later commands to trip over, and PARITOK_API_KEY always takes
precedence over the file.
Checks the backend is compressing, not merely reachable.
It deliberately ignores Paritok's /test, which has been measured reporting the GPU
online while /compress returned gpu_available: false and passed content straight
through. Instead it POSTs a fixed canary — an ASCII-banner helper — under a mismatched
refund intent. That pair returned empty 20/20 during Gate A, so a non-empty reply
means relevance filtering is not working, whatever /test claims.
resident scan <path> -i "<intent>" [-o residency.md]| flag | default | meaning |
|---|---|---|
--intent, -i |
required | what you are working on; the admission query |
--out, -o |
— | write the context pack here; - for stdout |
--budget |
160000 |
residency token budget; over it, refuse (exit 4) |
--concurrency |
3 |
parallel compression requests |
--dry-run |
off | estimate cost and wall clock, send nothing |
--redact |
off | mask detected secrets instead of refusing |
--guard |
off | conservative prefilter — see below |
--facts/--no-facts |
on | fact ledger and tombstones |
--without-paritok |
off | removal test: the same pipeline, no oracle |
--live/--no-live |
on | live residency monitor |
Secrets are gated by default. scan egresses a working tree to a third party, so
it refuses outright when it finds anything secret-shaped and requires explicit
--redact to proceed.
--guard is off, and that is a published negative result. The conservative
prefilter was the architectural centrepiece of the original design — the argument
that coverage was architectural rather than statistical. Two corpora said it changes
recall not at all and costs 304,651 extra tokens on a 1.43M-token corpus, because
force-kept segments are sent verbatim. It survives as an opt-in flag.
--without-paritok reports honestly. With the oracle removed nothing is dropped
or compressed, and the pack costs more than the source, because every entry still
carries a [REF:…] header. A removal test that showed a saving would be measuring
something other than Paritok.
resident ask <path> "<question>" # also needs ANTHROPIC_API_KEYMakes the repository resident, then runs the enumeration loop with the expand tool
over the pager. This is the only command that talks to a model provider.
Runs the pre-committed local baselines (uncompressed, ripgrep, prefilter-only, and optionally ripgrep with answer-key patterns) and writes a results file. No Paritok calls.
| code | meaning |
|---|---|
0 |
ok |
1 |
error |
2 |
usage — reserved, so a bad flag is never confused with a degraded run |
3 |
degraded — completed, but the numbers are not trustworthy |
4 |
refused — would not fit; refused rather than truncated |
130 |
interrupted; completed verdicts are cached, re-run to resume |
A degraded run exiting 0 is how a silent passthrough becomes a published "97%
saving". It exits 3, and savings are not printed at all.
Nothing was built until the behaviour was confirmed on the hosted backend rather than local q4 weights.
| # | assertion | result |
|---|---|---|
| A1 | drop verdict responds to intent | pass — 20 reps/cell, 80/80 calls, 0 errors |
| A2 | a drop is recorded as billed dashboard activity | pass |
| A3 | content and key attribution | pass |
| A4 | explicit kind honoured |
pass, 3/3 distinct outputs |
| A5 | verdict stable at 2000 vs 3000 tokens | pass, cap kept at 3000 |
| A6 | concurrency and throughput | 0.98 req/s at concurrency 3, 0/80 errors |
| A7 | truncation leaks SEG markers | not reproducible, check retained |
A1 crossed two documents with two intents, 20 repetitions per cell:
| document | matching intent | non-matching intent |
|---|---|---|
refund.py |
0/20 dropped | 20/20 dropped |
banner.py |
20/20 dropped | 0/20 dropped |
A1 was pre-registered with four branches, not three — including a "stochastic proceed" branch for a 40–90% empty-body rate. Specifying repetitions at all concedes that variance is expected, so leaving the partial-agreement cell without a rule would have been an invitation to rationalise afterwards. The observed behaviour landed in the deterministic branch.
A2 mattered because the claim is that a drop is a real, billed, attributable unit of work. Baseline was read twice, 45 seconds apart, to confirm the reporting backlog had drained; then 100 verified drops were issued and predictions recorded before re-reading:
| metric | baseline | predicted | observed |
|---|---|---|---|
| requests | 822 | 922 | 922 |
| tokens processed | 811,600 | 840,700 | 840,700 |
| tokens saved | 539,400 | 568,500 | 568,500 |
| ratio | 0.335 | 0.324 | 0.324 |
The alternative hypothesis — drops counted as requests but not as savings — predicted 0.358. A drop is credited as a 100% saving, exact to the token.
Corpus A — 12 sources, 1,289 segments, 1,430,065 tokens. Five Python libraries as installed packages at pinned versions (filelock 3.32.2, fsspec 2026.7.0, httpcore 1.0.9, joblib 1.5.3, playwright 1.62.0), plus seven further third-party repositories.
The library part is what pip install puts on disk, not what git clone does. That
is deliberate: an agent in a real environment reads site-packages continuously and
upstream repositories rarely. It is stated because a reduction figure is only
meaningful against a named denominator — and then verified: each library was
cloned at the tag matching its installed version and compared by content hash, and
245 of 248 .py files are byte-identical. The three exceptions are version.py,
_version.py and _repo_version.py, generated at build time.
Corpus B — the same 12 sources with the five libraries swapped for full clones at those tags. 2,275 segments, 2,150,959 tokens: a factor of 1.72 on the library part and 1.50 overall. The added content is tests, benchmarks, examples and documentation config, and it grows unevenly (filelock 3.15×, joblib 1.11×), so per-source results were expected to move by different amounts and possibly in different directions.
Per-source detail is published for the five named libraries. The other seven are
reported as third-party-01…07; they are other people's repositories and are not
ours to republish.
Reduction is measured over every token in the corpus, including sub-floor content sent verbatim:
Fidelity is atom retention by exact substring search, the same rule paritok-audit
scores by:
Every fidelity figure is computed twice — once with paritok-audit's extractor,
once with an independently written regex set (core/facts_alt.py) using a different
category scheme. If the system were memorising one extractor's quirks, it would fail
on the other.
Recall intervals are Wilson, not Wald. The normal approximation collapses to zero
width at
Ground truth is generated by a structural rule over the AST: a function is a site if it carries a retry decorator, or if a single enclosing loop contains both an except handler and a sleep call.
| arm | recall | 95% CI (Wilson) |
|---|---|---|
| ripgrep, human-written pattern | 13/20 — 65.0% | 43.3 – 81.9 |
| ripgrep, patterns derived from the answer key | 19/20 — 95.0% | 76.4 – 99.1 |
| Resident | 18/20 — 90.0% | 69.9 – 97.2 |
At
Five of the eight arms ask Paritok the same question and differ only in how they
treat the answer, so cost is
| arm | reduction | fidelity (scorer) | fidelity (independent) |
|---|---|---|---|
| stock | 49.4% ± 0.1% | 62.7% ± 0.1% | 64.6% ± 0.1% |
| resident | 60.6% ± 0.1% | 52.8% ± 0.1% | 54.5% ± 0.1% |
| per-segment intent | 53.7% ± 0.4% | 61.0% ± 0.4% | 63.2% ± 0.4% |
| fact-gated | 26.6% ± 0.2% | 78.2% ± 0.1% | 79.2% ± 0.2% |
| resident + tombstones | 58.9% ± 0.1% | 62.7% ± 0.1% | 63.8% ± 0.1% |
| resident + fact ledger | 52.3% ± 0.1% | 100.0% | 97.3% |
| stock + ledger (ablation) | 42.8% ± 0.1% | 100.0% | 98.2% ± 0.1% |
| per-segment intent + ledger (ablation) | 46.6% ± 0.4% | 100.0% | 98.0% ± 0.4% |
Spread is
No arm is beaten on both axes. That is the correct reading of the table, and the reason both axes are always reported together.
stock + ledger and per-segment intent + ledger exist to answer the obvious
objection: is the fact ledger a Resident advantage, or a universal post-processor?
The answer is universal. All three ledgered arms reach ~100% on the scorer and ~98% on the independent extractor. Resident's real advantage is narrower and should be stated as such: because Resident drops more segments, the same ledger costs it fewer tokens — 52.3% reduction against 42.8% and 46.6%.
100% scorer fidelity is circular by construction. The ledger is built from the scorer's own extractor, so of course the scorer finds everything. It is reported as a sanity check only. The defensible numbers are the independent extractor's results and the task-level evaluation below.
eval/task_eval.py generates answerable questions from each segment and applies three
checks — exact (the answer string appears), context (it appears within 200
characters of the symbol it belongs to), and relationship (a pair such as
raise ConfigError has both parts present, near each other).
The result is uncomfortable and worth publishing: exact rates reach 100%, while context rates sit at 3–6% and relationship rates at 6–10% across every arm, ledgered or not. The ledger reinjects atoms as a flat list, so the string survives but its association with its function or its exception handler is often lost.
Atom retention — the standard fidelity metric in this space — measures presence, not usability.
Two follow-up variants were built and measured against that finding:
| variant | reduction | independent fidelity | context | relationship |
|---|---|---|---|---|
| flat ledger (shipped) | 52.6% | 97.2% | 5.8% | 8.4% |
| grouped by enclosing def/class + verbatim pairs | 49.3% | 97.8% | 5.9% | 11.9% |
Grouping atoms under their enclosing symbol cost 2.31 points of reduction and moved the context rate from 5.8% to 5.9%, so it was built, measured and removed. Re-emitting broken pairs as verbatim snippets did work (8.4% → 11.9% for 0.73 points) and is documented in-source as the strongest candidate if that axis ever outranks size. Both results live in the code comments so the next person does not rebuild them.
Stated because a results section without one is not a results section.
-
Recall is measured at
$N = 20$ on real code, and the intervals overlap. The answer key comes from a structural rule over corpus A and does not transfer to a different file set. -
The agent loop has not been exercised at corpus scale.
core/agent.py, the pager and the eviction policy are implemented and unit-tested against mocked transport; the published benchmark measured the substrate — segmentation, admission, assembly, fidelity — and never involved a model provider. -
The fact ledger cannot restore single-word literals. Tested directly against
core/verdict.py: the extractor capturesgpu_unavailableandinvalid_key(snake_case matches its identifier pattern) but notpassthrough,timeout,malformed,refusedortruncated. Those are not atoms under any of its rules, so no ledger can put them back, however lossy the compression was. A reader of a pack can therefore lose three of the fiveDegradedReasonvalues with no marker saying anything is missing — unlike a drop, which at least leaves a tombstone. This is the concrete mechanism behind the low context and relationship rates above, and it is a property of the extractor rather than of the compressor. -
Comparison arms are reimplementations of each published strategy from its
description, not the authors' code. The fact-gated arm's level ladder depends on the
levelparameter, which is a confirmed no-op on the hosted backend, so that arm implements only its final fallback. -
30 of 1,289 corpus A segments returned
Degradedacross 8 of 12 sources. Runs containing aDegradedverdict exit 3 and report no saving. -
cl100kis used for sizing only. Billing figures come from provider-reported usage. - 100% scorer fidelity is circular, as described above.
Found by using Paritok properly, each one reproduced, and where it was ours to fix, fixed:
| defect | status |
|---|---|
| result cache keyed on content alone, so intent and level are ignored on repeat | PR #26 — ours, open |
| path short-circuit returns stale compression after a trailing function is deleted | PR #26 — a regression the first cache fix introduced |
a single line larger than CHUNK_SIZE fails with HTTP 400 |
PR #25 — ours, open |
/test reports GPU online while /compress returns gpu_available: false and passes content through |
reproduced 5× over 35 min; already filed by another contributor |
level accepted and ignored on hosted |
confirmed by the maintainer, issue #3 |
Python-urllib User-Agent rejected with HTTP 403, indistinguishable from a rejected key |
measured |
PR #26 is worth a note: it builds on someone else's cache-key fix, keeps their commit and credits them, and adds the repair for a regression that fix introduced — results were stored under the new wide key but still read through the old narrow one.
The largest finding is not in that table because it is a design issue rather than a
defect: compress() returns str for four distinct outcomes, so no caller can
separate “irrelevant to your query” from “the backend died.” That is the root
cause of
issue #20, where an
empty body is accepted as a summary and silently destroys a tool result. The fix
proposed there would repair the data loss but collapse the verdict into the failure
case; the typed-outcome version in this repository's adapter keeps both
distinguishable, and the completeness requirement makes a torn stream structurally
incapable of presenting as a verdict.
paritok is pinned at exactly 1.2.8, not >=, because 1.2.9 is announced to change
/stats semantics such that re-delivered originals fold onto the compressed side and
savings can go negative. A silent minor upgrade would change the substrate
underneath a published benchmark.
pip install -e .
export PARITOK_API_KEY=pk_live_...
resident doctor
resident scan <path> -i "where do we retry a failed operation after waiting?" -o residency.md
# full head to head: 12 sources x 8 arms x 3 repetitions
RESIDENT_TASK_EVAL_SAMPLE_RATE=0.13 \
RESIDENT_CORPUS=eval/selected_repos_B.json \
RESIDENT_CHECKPOINT=eval/fullrun_checkpoint_B2.json \
RESIDENT_RESULTS=eval/FULLRUN_RESULTS_B2.json \
python -m resident.eval.fullrun 3
# task-level evaluation, offline
python -m resident.eval.task_eval eval/fullrun_checkpoint_B2.json
# every published number, regenerated from the append-only log
python -m resident.eval.recompute eval/events.jsonleval/anonymize.py is committed so the one transformation applied to published
artifacts is auditable: third-party source identities are replaced with opaque ids.
It renames keys only — no measured value is read, computed or altered.
34 modules, 5,459 lines of source, 143 tests across 11 files. CI runs four
gates on every push — ruff check, ruff format --check, mypy --strict over the
whole package, and the test suite — and never contacts the Paritok endpoint:
every network interaction in the tests is a fake or a recorded fixture, because the
endpoint is slow, non-deterministic, and unavailable to forks.
Apache 2.0 — see LICENSE and NOTICE.
Built with Paritok.