-
v1.1.0 Stable
released this
2026-09-21 10:33:05 +00:00 | 0 commits to main since this releaseThe reading side. Nothing here changes how a bundle is built from a folder;
what changes is how a question finds its way into one, and how many bundles
one question can reach.Changed
- A new default ranking: BM25 over passages and titles. A concept is scored
on its best 500-character passage and on a title/path-weighted field, and the
two are fused by rank. A concept longer than 4 000 characters is delivered as
its answering passage, withpassage: {start, end, of}saying where in the
concept it sits. The previous fusion stays reachable as--ranking fusion.
A reader will see different excerpts, in a different order, for the same
question on the same bundle. - BREAKING for anyone who reads the payload: the contract is
okf-consumption/2.withheldis no longer a list with one entry per
concept left out; it is a mapping withtotal,by_rule,nearest(the
best-ranked drops by name, title and source document, 20 by default) and
complete. Measured on a large real bundle, the old list was about two
thirds of the written payload and none of it counted against the budget the
payload reported.--withheld-fullbrings the whole list back. The revision
was bumped so that code indexingwithheldas a list fails loudly instead of
reading the wrong thing.--withheld-titlesis retired. - The server and the generic skill are the standard way in, over a whole
folder.okf projectand the front page say it in that order: register
okf mcp --rootonce, on user scope, and every project can ask every bundle
under it; the skill beside a bundle is the supplement for someone who would
rather register nothing. Neither is made again when a bundle is rebuilt. okf skillwrites ONE generic skill by default, carrying a working
method and an answer form and no bundle's numbers, so it does not go stale
when a bundle is rebuilt.--for-bundlekeeps the per-bundle form.
okf projectputs it at.claude/skills/okf-consume-any/.
Added
- Several sub-questions in one call.
okf consume --question A --question B(andquestionson the server'sokf_ask) reads the bundle once, cuts
each sub-question as if asked alone and interleaves the deliveries under the
samekand byte limit. One question gives exactly the payload it gave
before. - A map per bundle.
okf cardand the server'sokf_describecarry
map: one line per source document with its concept titles in document
order, a numbered series folded into one line. The working method is to read
the map first and ask two to four sub-questions in the map's own words. - A signal for weak coverage. The payload's
coveragecarries
absent_terms(question words the bundle holds in no form) andweak(one
such word, or nothing delivered). It is a reading, not a verdict. - A folder of bundles in one command.
okf card <folder>shows every
bundle under it,okf consume <folder>asks every bundle in one call
(--bundle-idnarrows it to one), andokf checkreads that reply, holding
each payload to all 19 rules on its own. These are the same functions the
server runs. - A table fragment is read under its heading. A concept carrying the
proposer's mechanical table title is ranked and shown under the nearest
concept above it in its document; the excerpt keepsown_title. No bundle
byte moves. okf project --gate: the gate can be chosen when building a project,
and the bundle'slog.mdnames which one ran.okf checkgainspassage_malformedandsubquestions_unindexed
(19 rules).
Removed
- The old test track tied to one reference corpus is retired. Its gate
row, its adapters and the tests that read those bundles are gone; public
tests and gates run on invented material. The retrieval gate's premises were
re-measured for BM25.
Known limitations added
See Known limitations: a question worded
differently from the bundle reaches it first through the map's words, the
retrieval gate is red on rows 5, 7 and 8, and speed was not measured.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- A new default ranking: BM25 over passages and titles. A concept is scored
-
v1.0.0 Stable
released this
2026-09-20 19:57:02 +00:00 | 21 commits to main since this releaseAdded
- A document the gate refuses WHOLE is named in the run's own summary.
Measured 2026-09-20 against a real corpus of official documentation built
with the shipped default gate: 17 sources were refused outright, 16 of them
among its ordinary reference pages, and the summary said only
onefail_secureline and onequarantine_reviewline. The count of
documents the gate dropped was not there (rejected (coded)sums gate
refusals and extraction failures, which have different remedies), the names
were not there, and neither was the way out.okf buildnow prints a
Documents the gate refused WHOLEsection carrying all four — the count with
its denominator, the names (capped at ten, with the rest in the bundle's
log.md), the codes, and--gate nonefor a source you vouch for yourself —
and repeats it in one line on stderr, where a redirected stdout cannot hide
it.log.mdgains a bullet naming every refused document, uncapped. The
exit code does not move: the build is valid, every refusal is coded and the
bundle is a true record of what the gate allowed; what was wrong was the
silence. A run the gate refused nothing from is byte-identical, in the
summary and inlog.md. - A
Known limitationssection on the front page, high up and before the
install detail: the gate's measured refusals and the way out, the absent
ceiling on what one run pays for images, the three gates of this repository
that are RED and what each red row means for a user, what the content
accounting does not count, and the rough edges nothing is planned for. No new
measurement — every number was already taken. - The payload says what of the question it reached — a new top-level
coveragemember carrying three lists: the terms the pre-pass read the
question as, the terms no concept in the bundle answers, and the terms no
delivered excerpt answers. Without it a reader holding eight excerpts cannot
tell a bundle that ANSWERED its question from one that merely ranked
something; the two payloads have the same shape. Documented as SS 8 point 7
ofdocs/consumption-contract.md, and the generated consumption skill is
told to read it.- Facts, and no verdict, which is a measurement rather than caution. Two
readings were built and both falsified over 81 questions (16 synthetic,
65 across three real gold sets, 2026-09-20): the share of a question's
terms a delivered excerpt answers separates the synthetic controls at 0.33
against 0.50 and then REVERSES on real data, where covered questions run
down to 0.27 while one genuinely uncovered question sits at 0.71; and the
share of a bundle tying the best lexical match is ~0.00 for every question
in a large bundle, covered or not. Question style dominates the first and
corpus size the second, so a pre-pass emitting a verdict would assert
across corpora what was measured on one. - Contract change, and the cost to a consumer is a re-run. Every payload
grows the member; the checker does not read it, so a third-party pre-pass
that omits it stays conformant. The SS 7.4 known-positive moves with the
document it is measured on (14 721 / 375 → 16 389 / 417).
- Facts, and no verdict, which is a measurement rather than caution. Two
- The retrieval gate is measurable where it was assertable
(tools/okf_retrieval_gate.py, not shipped in the wheel):- Row 8 prints the identity of every bundle it measured — path,
bundle_idand content ref — beside the set's sha256. Measured the same
day: two builds of one consumer's corpus carrying the SAMEbundle_idat
different refs score differently on the same pinned set, which is why the
ref and not the id is what a row is attributed to. REAL_SET_PINSstates what each of the three real sets IS — questions,
fasit entries, controls and sha256 — so a self-written file in the right
shape is refused instead of reading1 of 1 | 3 of 3 | GREEN.- Row 5 reads the hold-out threshold as a number in [0, 1] and RUNS the
registered set against the registered bundle, printing
answered of asked = share against threshold.bool(threshold)was the
whole check, soreport-only; any number is acceptable for v1passed it. - Row 4's marking reads the payload's
coverage:UNANSWERED_BAR = 2/3,
swept and collapsing at both ends (at 0.50 eleven real covered questions
are marked; at 0.70 the row falls to 5 of 6). The margin is thin — 0.6087
against 0.6667 — and what it does not catch is published with it.
- Row 8 prints the identity of every bundle it measured — path,
Changed
- The two
pip installlines under "Install in detail" install
[extract]. The first screen installsllm-ingestion-okf[extract]and
those two omitted it, so a reader following the detailed instructions got a
build that reportsresolved converter path: unresolved (extractor_extra_missing)and reads no binary format. Two recipes, two
different installations. - Version
1.0.0. The scope this tool is finished at. It adds no
capability overv0.10.1; what it adds is that the tool says what it does
not do. After this tag the library is touched for defects found in its own
use, and the next round is Google OKF v0.3. - A withheld concept now carries the rule that actually decided it. The
source quota filters the WHOLE ranked candidate list rather than the top
k, so every over-quota candidate came backsource_quota_exceeded—
including the ones the RANK had already put outsidek, which the quota
only reached because it ran first. Measured on 25 real misses 2026-09-17:
13 of them were labelled by the quota and decided by the rank.
consume._fates_without_quotaasks the same cut what would have become of
each candidate with no quota in force, and the drop keeps THAT rule; only a
candidate the quota-off cut would have delivered is named as the quota's.
The budget step is lifted intoconsume._packand used by both, so the
quota-off fate is decided by the code the run itself uses. This moves the
rulestring a consumer reads for some withheld entries; no delivery, no
rank and no excerpt byte moves, and no committed payload in this repository
changed. The retrieval gate's row 3 goes 2 of 5 RED to 5 of 5 GREEN.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- A document the gate refuses WHOLE is named in the run's own summary.
-
v0.10.0 Stable
released this
2026-09-17 08:01:38 +00:00 | 115 commits to main since this releaseAdded
- A bundle carries the images its sources declare (0.10.0). Until now no
reader in this package fetched, named, described or copied a single image:
<img>'s attributes were never read, a NISO-STS<graphic>was walked past,
a PDF was opened for its text alone, the converter's markdown writer dropped
every picture, and the only writer into a bundle tookcontent: str. The two
lossiness warnings said so on every run, which made the loss honest and did
not make it smaller. Measured on R761 Prosesskoden:2025: the process text is
carried in full while 12Tabell N-Nand 9Figur N-Ncaptions stand over
nothing, so process 84's "toleranseklasse ... er gitt i tabell 84-2" points
at empty space.
Five readers place, one module decides.pdf(embedded image XObjects),
docx/pptx/odt/rtf(the converter's media, through--extract-media),
html/htm(<img src alt>, local paths and inline data URIs) andxml
(<graphic xlink:href>, resolved against the href and then against a sibling
graphics/).llm_ingestion_okf.assetsdecides what an image IS, what it is
called and how it is pointed at, so "carried N of M" means one thing across
all five..xlsxis deliberately excluded: a two-line block inside its pipe
tables would break the row locator read back out of them.
The bytes go toassets/at the bundle root under
<sha256[:12]>-<the source's own base name>, and the concept carries a
two-line pointer where the picture stood -- a markdown image, then the
source's own file name and the size in pixels. A PDF stream that is already a
file (DCTDecode,JPXDecode) is carried VERBATIM; raw samples are encoded
to PNG withzlibfrom the stdlib, so no new dependency and no rasteriser
version enters an asset's bytes or its content-addressed name. What this
encoder cannot express exactly -- a stencil mask, aDecodearray, CMYK,
anything but 8-bit samples -- is refused with a code and counted, never
approximated.
ON by default, with--no-assetsreproducing the pre-0.10.0 bytes.
Measured over the 43-document reference corpus, two builds of one commit:
453 -> 454 concepts, 865 -> 867 markdown files, 0 -> 2 964 assets (2 964
carried of 3 145 found, 4 622 pointers), 4.7 MB -> 115 MB, 2 414 s ->
3 088 s, peak RSS 6.26 -> 8.74 GB, and 422 of 865 markdown files differ. The
one new concept has a measured cause: the pointers are body text, so a
section holding 146 of that document's images grew from 19.0 % to 30.6 % of
the extracted text and crossed--outline-gate's 0.20 share clause.
log.mdstates it either way -- "N carried of M found", orNOT CARRIED
under--no-assets, so a bundle nobody looked for figures in cannot be
mistaken for a bundle of documents that had none. A concept on this
repository's own profiles also carriesimages: N, conditional, counted out
of the concept's own text.
The image bytes are NOT screened, and the log says so: the guard is
text-only, the pointer block passes the gate as body text, and the picture
beside it passes nothing.
Door C carries them too. Measured before the repair: importing a bundle
built with--assetsmerged 6 of 6 concepts and wrote noassets/at all,
so every pointer in the imported bundle named a missing file. Only the assets
a MERGED concept points at are carried -- an asset belonging to a refused
concept must not ride in on the back of a cleared one.
A proposed SPEC section 6.4 for the layout is in
docs/plan/okf-assets-section-6-4.md;_okf-canonicalis not edited from
here.
Fixed
-
A markdown image is no longer read as a cross-reference.
structure._LINKreads[...](target)and never looked at the character in
front of the bracket, so an asset pointer would have arrived in the index as
areferencesedge to a concept that cannot exist -- and the digits in an
asset's file name would have been read as a document number. The link's span
is still masked, so the number scan cannot see it either. -
okf buildnow runs a real guard, and the bundle says which one (F1).
From the day the command was packaged until 2026-09-15,corpus.measure
wired an unconditional approve-everything stub intoprocess_inboxand no
add_argumentcall anywhere in the package named a gate -- so the only path
most people use screened nothing, whilepyproject.tomlmade the guard a
MANDATORY runtime dependency and the README recommended a composition the
command line could not reach. Reported from outside byclaude-code-llm-wiki
and reproduced here before anything moved.
--gatetakesguard-trusted-source(the new default),
guard-user-uploadornone, and the name is written into the bundle's
section 9log.mdeither way, so a consumer holding a bundle can tell a
screened one from an unscreened one. An unknown name is refused rather than
resolved to the stub: falling back would reproduce the defect with an extra
step.okf projectowns no flag that moves a bundle's bytes and takes the
default; the corpus harness carries the same flag and the same default,
because a test holds the two paths byte-equal.
The default was chosen on a measurement, not on caution. Over the 453
concept bodies of the pinned reference bundle,PRESET_TRUSTED_SOURCE
returns the persist disposition on 453 of 453 whilePRESET_USER_UPLOAD
holds 1, taking one of the 39 source documents out. Neither tier waves
anything through: an invisible carrier and a CRITICAL finding fail secure at
both, measured against guard 1.4.0. Door B's own library default is
unchanged atPRESET_USER_UPLOAD-- an inbox drop is an untrusted upload,
an operator pointingokf buildat their own folder is not. The second tier
ships asguard_adapter.inbox_gate_trusted_source, the three-line adapter
that module's own docstring describes, rather than as a preset parameter.
The composition the README recommends is now tested. Before this change
grep -rl inbox_gate tests/gave ONE file with 0 occurrences ofsegment,
while the nine files passingsegmentation=all injected a local warn-stub:
no test ran a real guard verdict and a segmentation plan in the same call. -
A fenced code block no longer declares structure (F2). The proposer read
every line of the extracted text with the same grammars, so# Use the opus[1m] aliasinside a ```bash fence became a level-1 ATX heading. Two
effects, and the smaller one was the visible one: the document was REFUSED
entirely when the line carried[or](Door B validates a title fail-fast
and never repairs one) -- 5 of 191 pages of the reporter's corpus -- and the
concept TITLE was silently taken from somebody's shell session everywhere
else, on 62 of 191 pages (32.5 %).
No rule infind_candidatesreads a fenced line now: not ATX, not the
numbered grammar, not a table row, not a bold title, and not Arm D's outline
run, which selects from the whole line list and would otherwise let a fenced
install listing decide which run wins. Backtick and tilde fences, up to three
leading spaces, a closing fence at least as long as its opener, and
CommonMark's rule that a backtick fence's info string may not contain a
backtick -- that last one is what keeps a line holding only`okf build`
from silencing the rest of a document.
It lands unconditionally rather than behind a flag, and the exposure is
measured on the bytes: 0 of 865 concept files in the pinned default bundle
and 0 of the shipped fixtures and goldens that reach the proposer carry a
fence of either kind, so a rule that can only fire INSIDE a fence cannot have
moved anything this repository has measured. It is a defect, not a default
move.
Added
okf quality <bundle> --fasit <json>-- boundary recall against the
structure the source itself declares (G37b). The bundle-only gate returned
UNMEASUREDand exit 3 on the very arm it was built for, because no
bundle-only metric reaches it;boundary_share-- declared boundaries that
became a concept, over declared boundaries -- is the one metric measured that
orders the arms correctly, and it needs the publisher's own structure, so it
arrives as an input rather than as a constant. The fasit is a JSON list whose
rows carrytitleandnorm, validated at the door: a file that is not a
list, a row missing either key, or anything that is not JSON exits 2 with
the reason, never a quietUNMEASURED.
The normalisation was measured before the metric was built: stripping all
whitespace and lowercasing reproduces the fasit's ownnormfrom its own
titleon 2 761 of 2 761 rows (keeping only alphanumerics scores 58).
A boundary is recovered in either of two forms, and both are load-bearing:
a concept whose normalised title equalsnorm, or the pair of the concept's
own directory and its residual title -- because the numbering token a
publisher glues into a heading lands in the concept id on one route and in the
title on another. Measured on the known-good arm, the literal form alone
reaches 22 of 2 761 where the two together reach 2 759; on another
build of the same product the split is the exact opposite (2 727 literal, 0
paired). One bar, at the value measured on the pinned artifact: 2 759/2 761,
corpora = 1. It separates the known-bad arm at 1 148 of 2 761 (41.6 %),
which is now aFAILand exit 1 instead of exit 3.--fasitis an
assertion, likeokf consume --ref: a bundle of another product scores 0 of
2 761 (measured on two of them) and readsFAIL-- the assertion being wrong,
not the bundle. The bar rests on one product, and the run says so on every
boundary row.docs/2026-09-12-g37-terskler.mdSS 7 carries the premises
re-measured, the seven bundles, the interval any bar could sit in, and the two
R761 builds this one fails.
Unchanged
- Without
--fasitthe command is exactly what it was, held by a test: no
boundary row, and860019-mdb-100still exits 3. No version bump, no tag,
okf checkuntouched.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- A bundle carries the images its sources declare (0.10.0). Until now no
-
v0.5.0a2 Pre-release
released this
2026-07-31 18:50:39 +00:00 | 382 commits to main since this releaseThis is the pre-release the pilots pin.
v0.5.0a1was tagged and abandoned
unused — do not pin it. It carried agenerated.byactor that the spec owner
had already excluded, and it was caught before any pilot was notified.Fixed
-
OKF_V0_2'sgenerated.byactor isprocess:okf-ingest, not
process:llm-ingestion-okf. Commons decided the fixed id on this repo's own
proposal 2026-07-31, superseding option (d) chosen here 2026-07-27. The
exclusion isingest-spec.md:7-8, frozen on the spec being framework-neutral:
normalising our repo name into the id would force every other conformant
implementation to write it into its own output.Nothing in the wild carried the excluded value —
OKF_V0_2did not exist at
v0.4.0, and no pilot had been notified — so this costs a tag rather than a
migration. It is recorded rather than quietly folded in because the failure it
avoids is specific:actoris both the stamp written and the value owned back
(OwnershipPolicy), and recognition is one-way, so a pilot holding bundles
stamped with the excluded id would have hitcollision_unstampedon its own
files the moment the id was corrected.
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
0 downloads
-