Licence and ethics audit

Prepared 22 Oct 2026 at commit 4e6fbc4 for the capstone hand-in, and updated 27 Oct 2026 for the Phase 12 release (the dependency table now includes the documentation group, and section 5 covers the new scripts; section 6, on the release files, the public history and the GitHub Actions, is new; the former section 6 is now section 7). It covers every dataset and dependency, what the repository redistributes, and a final review that the repository describes how detectors decay and not how to evade them. It is an engineering audit, not legal advice; the researcher decides before anything is published.

1. This repository

Item

Licence

Evidence

DriftWatch code and documentation

MIT (LICENSE; ADR-0002)

pyproject.toml declares license = "MIT"; CITATION.cff repeats it

Distribution name

driftwatch-lifetime, import name driftwatch (ADR-0003); not the PyPI package driftwatch

README.md

pyproject.toml still carries the classifier Private :: Do Not Upload, which makes any upload to PyPI fail on purpose. It is removed only in the release commit, on the researcher’s explicit go (ADR-0003, docs/RELEASING.md). Nothing in this audit authorises a release.

The public repository will be Yathindra25KB/driftwatch-lifetime, created from a filtered copy of the development history (section 3). The development repository Yathindra25KB/Driftwatch- stays private as the archive.

2. Datasets

Dataset

Licence as stated

Used here

Redistributed

LAMDA (Haque et al.)

MIT, per the dataset card (docs/data_cards/lamda.md, verified 10 Oct 2026)

Feature files for Android, 2013 to 2025

No

BODMAS (Yang et al.)

BSD-2-Clause for the repository code; no separate licence is stated for the dataset files (docs/data_cards/bodmas.md, checked 20 Oct 2026)

Feature vectors for Windows PE

No

EMBER2024 (Joyce et al.)

Apache-2.0, confirmed on the dataset card on 20 Oct 2026 [L-30]

Not used (Tier 3 was not run)

No

AndroZoo

Academic key; redistribution forbidden

Not used

No

SOREL-20M

Own terms, not verified

Not used (excluded in the build guide)

No

Decision of 22 Oct 2026: the BODMAS dataset files carry no stated licence. The repository says only “used as published by its authors”: it does not redistribute them, and the build downloads them from their own source into data/, which is not committed. The authors were not asked; doing so is optional.

3. What the repository redistributes

  • Only the synthetic fixture, plus one two-row aggregate table of its run (src/driftwatch/_golden/smoke_table1.csv, shipped in the wheel so that driftwatch smoke works without a clone; a test keeps it equal to the locked golden file). The fixture (tests/fixtures/synthetic/, generated by scripts/make_fixture.py, seeded). tests/test_fixture_regenerates.py checks that it is what the generator writes and that it stays under 1 MB.

  • data/ and results/ are git-ignored; the guard hook blocks git add of either, and tests/test_repo_invariants.py fails if any file under them is tracked (apart from data/manifest.json, which holds hashes and source URLs, not data).

  • Process documents: docs/source/ (the build guide, the implementation plan and the phase prompts: two PDFs and one Markdown file) is no longer tracked: it was removed from the index and added to .gitignore on 22 Oct 2026 at the researcher’s decision, because no licence is stated for those documents. The files stay on the researcher’s disk, and the repository’s history still contains them until it is rewritten, which was not done. .claude/ (hooks, agent definitions, rules) stays tracked as evidence of the guardrails.

  • Tables under reports/tables/ are aggregates of the study’s own predictions (per-arm A-AUT, counts, intervals), not dataset rows.

  • The report quotes short passages (a phrase or a sentence) from abstracts, each with its source and access date in the claims ledger (rows L-01 to L-33); no paper is reproduced.

4. Dependencies

Read from the installed metadata of every package in uv.lock by scripts/list_licences.py (no network; rerun with uv run python scripts/list_licences.py). 84 packages (85 entries in the lock, the project itself excluded): 11 direct runtime, 4 direct development, 4 direct documentation (the docs group, used only to build the site and never part of the wheel), the rest transitive. The runtime dependencies are the only ones a user of the wheel installs.

Package

Version

Licence

Read from

Kind

accessible-pygments

0.0.5

BSD-3-Clause

License

transitive

alabaster

1.0.0

BSD License

classifier

transitive

anyio

4.15.1

MIT

License-Expression

transitive

babel

2.18.0

BSD-3-Clause

License

transitive

beautifulsoup4

4.15.0

MIT License

License

transitive

certifi

2026.10.23

MPL-2.0

License

transitive

cfgv

3.5.0

MIT

License

transitive

charset-normalizer

3.5.2

MIT

License

transitive

click

8.5.0

BSD-3-Clause

License-Expression

transitive

cloudpickle

3.1.2

BSD-3-Clause

License

transitive

colorama

0.4.6

BSD License

classifier

transitive

contourpy

1.4.0

BSD-3-Clause

License-Expression

transitive

cycler

0.12.1

BSD License

classifier

transitive

distlib

0.4.4

PSF-2.0

License

transitive

docutils

0.22.4

Public Domain; BSD-2-Clause (installed files)

reviewed (docs/licence_audit.md)

transitive

filelock

4.2.4

MIT

License-Expression

transitive

fonttools

4.67.0

MIT

License

transitive

fsspec

2026.9.0

BSD-3-Clause

License-Expression

transitive

furo

2025.12.19

MIT License

classifier

direct, documentation

gdown

6.4.2

MIT

License

direct, runtime

h11

0.16.0

MIT

License

transitive

hf-xet

1.7.0

Apache-2.0

License-Expression

transitive

httpcore2

2.16.0

BSD-3-Clause

License-Expression

transitive

httpx2

2.16.0

BSD-3-Clause

License-Expression

transitive

httpx2-jsfetch

not installed

UNKNOWN

-

transitive

huggingface-hub

2.3.0

Apache-2.0

License

direct, runtime

hypothesis

6.170.12

MPL-2.0

License-Expression

direct, development

identify

2.6.20

MIT

License

transitive

idna

3.20

BSD-3-Clause

License-Expression

transitive

imagesize

2.0.1

MIT

License-Expression

transitive

iniconfig

2.3.1

MIT

License-Expression

transitive

jinja2

3.1.6

BSD License

classifier

transitive

joblib

1.6.0

BSD-3-Clause

License-Expression

transitive

kiwisolver

1.5.1

BSD License

classifier

transitive

lightgbm

4.7.0

MIT

License-Expression

direct, runtime

markdown-it-py

4.2.0

MIT License

classifier

transitive

markupsafe

3.0.4

BSD-3-Clause

License-Expression

transitive

matplotlib

3.11.2

Python Software Foundation License

classifier

direct, runtime

mdit-py-plugins

0.6.1

MIT License

classifier

transitive

mdurl

0.1.2

MIT License

classifier

transitive

myst-parser

5.1.0

MIT License

classifier

direct, documentation

narwhals

2.28.0

MIT

License-Expression

transitive

nodeenv

1.11.0

BSD

License

transitive

numpy

2.5.4

BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0

License-Expression

direct, runtime

packaging

26.3

Apache-2.0 OR BSD-2-Clause

License-Expression

transitive

pandas

3.1.0

BSD-3-Clause

License-Expression

direct, runtime

pillow

13.0.0

MIT-CMU

License-Expression

transitive

platformdirs

4.13.6

MIT

License-Expression

transitive

pluggy

1.7.0

MIT

License

transitive

pre-commit

4.7.0

MIT

License

direct, development

psutil

7.2.2

BSD-3-Clause

License

direct, runtime

pyarrow

26.0.0

Apache-2.0

License-Expression

direct, runtime

pygments

2.21.0

BSD-2-Clause

License-Expression

transitive

pyparsing

3.3.3

MIT

License-Expression

transitive

pysocks

1.7.1

BSD

License

transitive

pytest

9.1.1

MIT

License-Expression

direct, development

python-dateutil

3.0.0

Dual License

License

transitive

python-discovery

1.6.5

MIT

License-Expression

transitive

pyyaml

6.0.3

MIT

License

direct, runtime

requests

2.34.2

Apache-2.0

License

transitive

roman-numerals

4.1.0

0BSD OR CC0-1.0

License-Expression

transitive

ruff

0.17.3

MIT

License-Expression

direct, development

scikit-learn

1.9.1

BSD-3-Clause

License-Expression

direct, runtime

scipy

1.18.1

BSD License

classifier

direct, runtime

six

1.17.0

MIT

License

transitive

snowballstemmer

3.1.1

BSD-3-Clause

License

transitive

sortedcontainers

2.4.0

Apache 2.0

License

transitive

soupsieve

3.0.4

MIT

License-Expression

transitive

sphinx

9.1.1

BSD-2-Clause

License-Expression

direct, documentation

sphinx-basic-ng

1.0.0b2

MIT License

classifier

transitive

sphinxcontrib-applehelp

2.0.0

BSD License

classifier

transitive

sphinxcontrib-devhelp

2.0.0

BSD License

classifier

transitive

sphinxcontrib-htmlhelp

2.1.0

BSD License

classifier

transitive

sphinxcontrib-jsmath

2.0.0

BSD License

classifier

transitive

sphinxcontrib-mermaid

2.1.1

BSD-2-Clause

License-Expression

direct, documentation

sphinxcontrib-qthelp

2.0.0

BSD License

classifier

transitive

sphinxcontrib-serializinghtml

2.0.0

BSD License

classifier

transitive

threadpoolctl

3.7.0

BSD-3-Clause

License-Expression

transitive

tqdm

4.70.1

MPL-2.0 AND MIT

License

transitive

truststore

0.10.5

MIT

License-Expression

transitive

typing-extensions

4.16.0

PSF-2.0

License-Expression

transitive

tzdata

2026.5

Apache-2.0

License

transitive

urllib3

2.8.0

MIT

License-Expression

transitive

virtualenv

21.15.0

MIT

License-Expression

transitive

Notes:

  • httpx2-jsfetch is locked only for the emscripten (Pyodide) platform, so it is never installed on Windows or Linux and has no local metadata. Its licence was read by hand from its PyPI record on 22 Oct 2026: BSD-3-Clause.

  • Weak copyleft (MPL-2.0): certifi, hypothesis, tqdm. hypothesis is a development dependency. MPL-2.0 is file-level copyleft; none of these packages is modified or bundled into a distribution by this repository, which installs them from PyPI.

  • Composite or dual expressions (for example numpy: BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0; packaging: Apache-2.0 OR BSD-2-Clause; python-dateutil: “Dual License”, BSD-3-Clause or Apache-2.0 per its own text) are as the packages state them.

  • No package is GPL or AGPL, as installed. One metadata label needed a human reading, and the lister carries a version-pinned override for it (REVIEWED in scripts/list_licences.py, tied to the exact version, so a new version is read from its metadata again): docutils 0.22.4 reports “Public Domain; BSD License; GNU General Public License (GPL)” because its source tarball ships one GPL-3 file (tools/editors/emacs/rst.el, an Emacs mode) that is not part of the installed package; the files that are installed are public domain or BSD-2-Clause (its COPYING.rst, read 27 Oct 2026). docutils is a documentation-build dependency only.

  • Vague labels, read on 27 Oct 2026: nodeenv 1.11.0 ships a BSD-style three-clause licence text; python-dateutil ships an Apache-2.0 licence for newer contributions and a BSD-3-Clause licence that applies to all code (its own “dual license” text; read for 2.9.0.post0 on 27 Oct 2026 and again for 3.0.0, the version the 28 Oct 2026 dependency refresh resolves to, with the same structure); PySocks 1.7.1 states “BSD” in its metadata and ships no licence file (read from metadata only). All three are permissive; none is bundled into the wheel.

  • Runtime fetch of Mermaid. The documentation site draws its diagrams with Mermaid (MIT), which the page loads from cdn.jsdelivr.net at view time (version pinned by sphinxcontrib-mermaid). It is not vendored in the repository or the wheel; offline, the diagrams show as their source text.

5. Ethics review

Checked on 22 Oct 2026 against docs/ETHICS.md and CLAUDE.md hard rules 1 and 12:

Check

Result

No malware, binary or decompiled code is downloaded, opened, run or redistributed

The code reads pre-extracted feature files only; the only data committed is the synthetic fixture

No evasion tooling and no adversarial-example generation

A case-insensitive search of src/ for evasion, evade, adversarial, perturb, attack, obfuscat, payload and exploit finds no match. The only uses of subprocess run git (code version, tag check)

No network use beyond fetching datasets, checking references and the maintenance scripts

Checked 27 Oct 2026 by searching src/ and scripts/ for urllib, urlopen, requests, httpx, huggingface_hub, gdown, http.client and socket: five files open connections. src/driftwatch/data/download.py fetches the datasets (Hugging Face, Google Drive); scripts/check_bib.py calls Crossref and arXiv; scripts/arxiv_audit.py reads the arXiv API; scripts/dataset_watch.py reads the Hugging Face and GitHub APIs; scripts/zenodo_dry_run.py talks to sandbox.zenodo.org only when run by hand with a token that is read at a prompt and never stored. The development guard allows exactly these hosts (ADR-0001)

The search for evasion terms, repeated on the release files

Case-insensitive search of src/, scripts/, tests/, .github/, .claude/skills/, the architecture pages, the maintenance, release and roadmap pages, README.md, CONTRIBUTING.md, SECURITY.md and CHANGELOG.md for evasion, evade, adversarial, perturb, obfuscat, payload, exploit and bypass, on 27 Oct 2026. Every match is benign: policy text that declines such requests (README, CONTRIBUTING, SECURITY, the issue forms, MAINTENANCE, the extension page), a JSON “payload” in hook tests, a test that perturbs a run to check that a comparison fails, and the guardrail suite’s own “adversarial review” of the guard hook. No evasion or adversarial-example code exists

The issue forms and the contribution policy refuse evasion requests

CONTRIBUTING.md (“Not accepted”), SECURITY.md (“Out of scope”) and the bug-report form say that such requests are declined; the triage playbook tells the maintainer to decline and close them

The text describes decay, not defeat

Chapter 4 section 4.4 describes adversaries at survey level, says the study does not model an adaptive adversary, and contains no recipe; chapter 8 section 8.4 and docs/ETHICS.md say the same

Dual use

Knowing how fast a detector decays and when retraining pays could in principle help an adversary time an attack; the study measures natural drift on public datasets, reports aggregate effects, and offers no method to cause drift. A sentence on this was added to chapter 8.4 on 22 Oct 2026 at the researcher’s decision.

Labels

LAMDA’s labels are antivirus-based with an unpublished scan date [D-16]; BODMAS’s labelling is not described on its project page [D-17]; both are stated as limits in chapter 8

Personal data

None: the feature files describe software, not people

AI-assistance disclosure

Stated in report/ch00_front_matter.md and docs/ETHICS.md; the faculty’s policy is not yet known (docs/PHASES.md)

6. Release files and tools (Phase 12)

What a release contains. The wheel and the source archive are built by uv build; scripts/check_release.py (run in the release workflow and by a slow test) opens both and fails on any file under data/, results/, docs/source/, .claude-state/, .venv/ or .cache/, any .env or local settings file, any dataset-shaped file (.parquet, .npz, .npy, .zip) outside the synthetic fixture, any key or certificate, a wheel over one megabyte and a source archive over five. The only data-shaped files that may ship are the synthetic fixture (source archive only) and smoke_table1.csv, a two-row aggregate table of the fixture run that the wheel carries so that driftwatch smoke works without a clone. Built on 26 Oct 2026: wheel 203 kB, source archive 163 kB.

The public repository’s history. The development history contains docs/source/ (course PDFs and phase prompts with no stated licence), which was untracked on 22 Oct 2026 but remains in old commits. The public repository is therefore created from a filtered copy of the history made with git filter-repo --path docs/source --invert-paths, followed by checks that git log --all -- docs/source is empty, that no blob is larger than ten megabytes, and that no secret pattern is present; the mapping from old to new commit hashes is committed (docs/commit_map.csv) so the commits cited in docs/CLAIMS.md stay findable. The step is part of the researcher-gated release procedure and has not been done.

GitHub Actions used by the workflows, pinned to commit hashes with the version in a comment. Licences read from each repository on 27 Oct 2026:

Action

Licence

Used in

actions/checkout

MIT

CI, docs, release, audit

astral-sh/setup-uv

MIT

CI, docs, release

actions/setup-python

MIT

release, clean room, arXiv audit

actions/upload-artifact, actions/download-artifact

MIT

release, docs, clean room, arXiv audit

pypa/gh-action-pypi-publish

BSD-3-Clause

release (Trusted Publishing; no token stored)

Services. PyPI, TestPyPI, GitHub (Actions, Pages, Releases), Zenodo and its sandbox are used under their free terms; no secret is stored in the repository (Trusted Publishing uses short-lived OpenID Connect tokens). A Zenodo DOI cannot be deleted, so the release workflow creates the GitHub Release as a draft and the researcher publishes it by hand.

7. Not done here

No upload to any package index, no DOI, no change of repository visibility, no filtered public history, no tag, no pending publisher registered. Each of those needs the researcher’s explicit go (docs/RELEASING.md).