0002 provenance and the allowed references - CyrilB1531/lodestar GitHub Wiki
0002 โ Provenance and the allowed references
Status: accepted ยท Date: 2026-09-20
Context
This repository is published on GitHub and on nuget.org, which is distribution under
every licence involved, and the obligations have applied since the first commit. Five
records settled the question one occasion at a time: 0003 set the project's own
licence and the allowed-source rule; 0010 chose Snowball over the nltk corpus for
the stop-word lists; 0082 added scipy to the named references; 0084 vendored the
Llama-2 tokenizer under a licence that is not permissive; 0099 refused
scikit-survival on its licence rather than on its quality. They are merged here, with
each library's licence re-read from the wheel installed against tools/requirements.lock.txt
rather than carried over from the record that named it.
Three things the pins say that the merged records do not, found while re-reading them:
tools/requirements.txtcites decision 0098 for thescikit-survivalrefusal and decision 0090 for thesnowballstemmermeasurement. The records are 0099 and 0091; 0098 is the normal quantile and 0090 is Finnish. The pins are right, the citations are off by one.THIRD-PARTY-NOTICES.md's development-only table names fourteen libraries and misses six that are pinned and read today: scipy, mapie, statsmodels, rake-nltk, keybert, summa. scipy is the conspicuous one, since 0082 exists to admit it.- numpy's wheel declares
BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0, for the components it vendors; the notices file records BSD-3-Clause alone. Every term in that expression is permissive, so the rule below is satisfied either way.
Decision
Lodestar is Apache-2.0, and a reference library may be read for its behaviour only โ its inputs, its outputs, and where one of its branches cedes to the next โ and only when its own licence is permissive; a copyleft reference is read for nothing, and no reference of any licence is transcribed.
Sources rank, in order of preference: published papers and pseudo-code, which are not
protectable; textbooks and documentation; then a permissively licensed implementation as
a behaviour reference. What crosses over is the observable behaviour and analogous
naming, never the source. Running such a library to generate test data creates no claim
over the output, and the corpora under tests/oracles/ are that output.
The allowed references
Read from each installed wheel's METADATA, not from PyPI's field โ 0075 found that
field unreliable and 0099 re-found it. Versions are the pins in
tools/requirements.txt, tools/requirements-nodeps.txt and the resolved lock.
| library | pinned | licence | admitted by |
|---|---|---|---|
| rapidfuzz | 3.14.6 | MIT | 0003 |
| jellyfish | 1.2.1 | MIT | 0003 |
| textdistance | 4.6.3 | MIT | 0003 |
| scikit-learn | 1.9.0 | BSD-3-Clause | 0003 |
| scipy | 1.18.1 (lock) | BSD-3-Clause | 0082, for the Kolmogorov dispatch table |
| doublemetaphone | 1.2 | Artistic-2.0 | 0075 |
| nltk | 3.10.3 | Apache-2.0 โ the code only, never the corpora | 0008; bounded by 0010 |
| snowballstemmer | 3.1.1 | BSD-3-Clause | 0091 |
| tokenizers | 0.23.2 | Apache-2.0 | 0017 |
| sentencepiece | 0.2.2 | Apache-2.0 | 0013 |
| numpy | 2.5.3 | BSD-3-Clause and four other permissive terms | 0003's rule |
| mapie | 1.5.0 | BSD-3-Clause | 0070, applied again by 0143 |
| statsmodels | 0.15.0 | BSD-3-Clause | 0096 |
| lifelines | 0.30.3 | MIT | 0099 |
| rank-bm25 | 0.2.2 | Apache-2.0 | 0003's rule (#573) |
| datasketch | 2.0.0 | MIT | 0108 |
| simhash | 2.1.2 | MIT | 0003's rule (#602) |
| rake-nltk | 1.0.6 | MIT | 0077 |
| keybert | 0.9.0, --no-deps |
MIT | 0078 |
| summa | 1.2.0, --no-deps |
MIT | 0077 |
difflib is read too, and is not pinned: it is CPython's standard library, under the PSF
licence, and arrives with the interpreter. Every library above is a development
dependency โ none is referenced by a shipped package, and none is redistributed.
The refusals
| refused | licence | record |
|---|---|---|
python-Levenshtein |
GPL | 0003 โ not transcribed, and not even run to generate oracles, as a matter of hygiene |
abydos |
GPL | 0003's rule, applied |
scikit-survival |
GPL-3.0-or-later, from its PyPI license_expression |
0099 โ the reason on file is licence, not unavailability |
scikit-survival is the nearest survival reference in any language, and NuGet had none
at all on 2026-09-09. It was still refused, and lifelines (MIT) took the oracle.
The two exceptions, each limited to its artifact
The Snowball stop-word lists (0010). BSD-3-Clause, five languages โ French, German,
Italian, Portuguese, Spanish โ pinned by SHA-256 in tools/fetch_stopwords.py and
compiled into Lodestar.Text. They are the exception to read but do not redistribute:
they are the one resource the packages ship rather than merely consult, so the copyright
notice and the licence travel with them in NOTICE and THIRD-PARTY-NOTICES.md. The
exception covers those five files and nothing else. StopWords.English stays
scikit-learn's 318-word list, for the stop_words="english" parity it promises, and the
nltk stop-word corpus is not vendored in whole or in part โ nltk_data classifies it
as unclarified, and the Apache-2.0 on nltk's code does not reach it.
The Llama-2 tokenizer.json (0084). The LLAMA 2 COMMUNITY LICENSE AGREEMENT is not
an OSI licence and not permissive. The exception is this artifact alone and does not
relax the list above: the Agreement, its notice and its acceptable-use policy are vendored
complete under docs/vendored/llama2/, the file is pinned by SHA-256 and corroborated
against a second mirror by tools/fetch_llama2_mistral_tokenizers.py, and what is
committed is the vocabulary, the merge table and the pipeline flags. Every future
non-permissive source needs its own record; this one grants nothing by analogy.
The two hard rules
- Never transcribe GPL-licensed code. Implement from the published algorithm description. Reading a reference implementation to diagnose one failing case is diagnosis; deriving the implementation from it is not, whatever the language. This is why the stemmers and the phonetic encoders are original implementations, and the oracle is what proves the behaviour matches without the source needing to.
- Never commit model weights. Test fixtures are small and synthetic; a vocabulary is
fetched against a pinned SHA-256 by
tools/fetch_gpt2_bpe.py,tools/fetch_xlmr_vocab.py,tools/fetch_llama2_mistral_tokenizers.pyandtools/fetch_stopwords.py, each of which fails loudly when the upstream bytes move rather than producing a different library in silence.
Consequences
- Adding a reference means reading its licence out of the wheel and its transitive
graph the same way โ
0099's table is the worked example, where two oflifelines' dependencies reportLicense: UNKNOWNin legacy metadata and carry MIT in the wheel. A blank field is not a licence and is not a refusal either. - A new reference lands in
tools/requirements.txt(ortools/requirements-nodeps.txt, under0078's closure test) and inTHIRD-PARTY-NOTICES.mdin the same commit. The six omissions named in the Context are a debt against that rule, not a relaxation of it. - A source that is not permissive is refused unless a record argues it, artifact by artifact, and records the conditions its licence attaches and how each is met.
- A branch-selection question settled by reading a permissive reference's own dispatch โ
rather than a formula derived independently โ is behaviour, and this record is what it
cites;
Internal/Kolmogorov.cs's long comment remains the line-numbered account of what was read from scipy. - Shipped resources are attributed where they ship; development references are attributed for traceability and are redistributed nowhere.