Files
remove-ai-watermarks/docs/development.md
T
Victor KuznetsovandClaude Opus 5 e85307f1c0 Scrub private infrastructure detail and move the GPU harnesses out
The Content Seal manifest named the production GPU worker in its provenance
column and in two row keys, several docstrings described their sources as user
uploads from the private corpus, and that corpus was called by the storage
product holding it. Each is now what a public reader can check: a pipeline and
strength, material that is not publication-cleared, and a private corpus. The
corpus test follows the renamed rows. Deployment and tier detail goes the same
way, since which backend each hosting tier can afford is a product decision,
not a library fact.

Twelve harnesses that need a cloud GPU account leave scripts/. The research
pages that cite their findings name them as harnesses kept outside this
repository and stop implying a reader can rerun them; the tracked inputs and
recorded verdicts remain the durable record, and the offline analysis step
stays here with its test. A development invariant states the rule so the next
harness is not added back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:29:12 -07:00

5.2 KiB

Development

Standalone evaluation, calibration, and release utilities are catalogued in scripts/README.md. They are maintainer tools rather than installed commands, and their local data inputs remain outside the repository.

Read this reference for environment setup, dependency recovery, CI behavior, and fixture policy. The always-loaded invariants remain in .claude/rules/development.md.

Local environment

  • Use uv sync --frozen --extra dev and add only the feature extras needed for the task.
  • Do not use uv pip install for development tools. It can re-resolve uv.lock outside the compatible ML dependency set.
  • A default-only sync removes every pixel and model package by design. Package imports remain light through lazy exports.
  • On an unreliable connection, sync dev plus only the required feature extras, such as diffusion, and run the checks directly instead of downloading every optional learned backend.
  • Run uv from the repository root or it may create a bare environment without the project dependencies.

maintain.sh starts with uv sync --all-extras, so a lean environment is replaced whenever the gate runs. Syncing back down can leave opencv-python-headless half-removed: import cv2 then succeeds against an empty namespace while cv2.INTER_LINEAR is gone, which surfaces as a suite that stalls or reports hundreds of unrelated failures. Repair it with uv sync --frozen --extra dev --reinstall-package opencv-python-headless rather than re-reading the diff.

Pyright is only meaningful with the extras its imports need. Scoped to src/, a lean environment reports TrustMark, transformers and huggingface_hub as unresolved, which reads as a type error and is not one; add --extra trustmark --extra classify before believing it.

The optional TrustMark decoder downloads weights into its installed package directory. After pruning that extra, a leftover weights directory can make availability checks see an empty namespace package. If Pyright reports an unknown TrustMark import and find_spec("trustmark") returns a loader-less spec, remove that regenerable remnant from the active virtual environment and resync.

Known security-gate blocks

maintain.sh fails while PyPI ships no fixed release for a transitive CVE. Current case (triaged 2026-08-17): lightning 2.6.5, pulled only by the optional trustmark extra, carries PYSEC-2026-3624 (RCE via load_from_checkpoint on an attacker-crafted checkpoint). The vulnerable API is unreachable here, because the TrustMark decoder loads only its own pinned weights downloaded from the TrustMark release, never a user-supplied checkpoint. The upstream fix is merged but unreleased, and ignores are never added, so run and report the remaining core checks (Ruff, Pyright, tests) separately until a fixed lightning release lands; bump it with uv lock --upgrade-package lightning as soon as one does. The gate prints the same advisory twice, as PYSEC-2026-3624 and as its alias GHSA-qqmf-gpg7-g8gw (CVE-2026-58659); the 2022.6.15 fix version on the second row belongs to the retired calver line and is not an upgrade from 2.6.5, so neither row is actionable.

CI

.github/workflows/test.yml runs Ruff, a test matrix over every supported Python minor with default plus development dependencies, cross-platform coverage at the oldest and newest minors, and a separate job that installs ffmpeg on Ubuntu to run the full-clip video test. Diffusion and model-running tests skip in that matrix; metadata, identification, visible removal, the DWT-DCT decoder, and the OpenCV eraser remain covered across operating systems.

Keep uv.lock compatible with uv sync --frozen. Dependency pull-request checks use GitHub's merge result against current main; if main moves, merge it locally and rerun the full gate because a newer linter can expose stale directives in later code.

test.yml runs one concurrency group per ref with cancel-in-progress: true, so a newer push cancels the previous run mid-flight. A cancelled run is not a failure verdict: the superseding run's head includes the cancelled commits as ancestors, so watch that run to completion instead of retrying the push.

Release and distribution behavior is canonical in release-and-distribution.md.

Fixture and data policy

../data/README.md is the source of truth:

  • executable provenance fixtures live under data/fixtures/;
  • minimal controlled detector inputs live under data/calibration/;
  • canonical provider-oracle originals and their manifests live under data/synthid/;
  • evaluation-only ground truth lives under data/evaluations/;
  • runtime detector assets live in the package; unregistered research candidates remain outside the shipped wheel.

Store each binary once. Point tests and manifests at its canonical path. Keep generated and cleaned outputs outside the repository and retain only reproducible public records allowed by the data policy.

Use synthetic byte blobs for unsupported format paths and deterministic generated negatives where a real negative fixture is unnecessary. Detection and removal tests must preserve their format-specific invariants.