download-artifact@v8 extracts the only pattern-matched artifact directly
into the target path, without the artifact-name directory the resolve
step assumed, so every workflow_run verification died at
"No distributed release identity found" before checking a single
surface. The directory-name attempt check now applies only when the
artifact directory exists; a flat identity is still pinned by the
run-id and attempt-eligibility asserts. The workflow_run path of
5c6588b had never executed: v0.38.0's run failed on later checks and
the surfaces were confirmed by a manual dispatch.
The new test drives the real workflow script against the flat layout
and reproduced the production failure before the fix.
pre-commit: 1) maintain.sh - exit 2 (uv-secure on the documented
lightning/accelerate blocks, unchanged lock; core checks separately:
C2PA sync current, Ruff clean with no rewrites, Pyright src/ 0 errors,
2360 passed 3 skipped); 2) /simplify - single-pass four angles, clean;
3) docs sync - grepped distributed-release over docs/: the one mention
stays accurate; 4) CLAUDE.md - improver grade A earlier this session,
revise: no additions
pre-commit: 1) maintain.sh - exit 2 (uv-secure on the documented
lightning PYSEC-2026-3624/GHSA-qqmf-gpg7-g8gw and accelerate
GHSA-4j2p-28q2-5m79 blocks, no fixes on PyPI; core checks separately:
C2PA sync current, Ruff clean with no rewrites, Pyright src/ 0 errors,
2359 passed 3 skipped); 2) /simplify - single-pass four angles, clean;
3) docs sync - grepped 0.38.0/0.39.0 over README, docs/, skills/,
rules/: no stale refs (0.38.0 hits are feature-first mentions or the
diffusers dependency); 4) CLAUDE.md - improver grade A, no changes;
revise: no additions
Round unsharp output in its existing buffer before uint8 conversion, preserving
constant images across OpenCV builds. Compare explicit stored WebP decodes.
Use host-absolute launcher fixtures and restrict Ubuntu Bash harnesses to POSIX.
Document the CI findings and the unresolved Dependabot Transformers/tokenizers
candidate conflict. Keep the existing model dependency constraints.
Repair image and metadata publication contracts, detection routing, research
artifact validation, release verification, and the published agent skill.
Refresh the dependency lock and reconcile documentation with verified behavior.
Add regression coverage and record the completed audit and corrected VideoSeal
measurements. Preserve the existing Accelerate and Lightning versions.
Validation: Ruff and Pyright pass; 2358 tests pass with 3 skipped. The maintenance
gate exits 2 on the documented Accelerate and Lightning security findings.
The ClawHub publication of 1.0.3 has sat in pending.publication with
succeeded static scans and null primary verdicts; version numbers stay
reserved, so the only re-queue path is a new version. No content change.
bytedance generator class (surgical six-head provider.pt), tc260 group
veto, stable-name receipt-gate.npz with the threshold inside the
artifact, snapshot-tolerant loader, weights pinned to revision
4c276376 (published via photo-classify-freeze-2026-09-07 release).
The ignore rule landed with a comment naming the private product, its storage
provider, the private rule file, and the size of the customer set. That text is
the disclosure the rule exists to prevent, so it says what a public reader needs
instead: these trees are local-only and not publication-cleared.
`data/research/` gets the same tracked rule as `data/spaces/`. It held 68 GB
behind `.git/info/exclude` alone, which no clone has, so a fresh checkout could
commit the whole corpus with nothing to stop it, and a test now pins both
entries.
A first draft of that test also carried a denylist of private identifiers,
which published six of them into a tracked file to keep two out, and only its
own self-exclusion hid that. The mechanized half is now the one that discloses
nothing: no cloud GPU harness under `scripts/`. Reading the ignore entries
rather than the file text matters too, because a comment naming
`data/research/README.md` satisfied the first assertion with the rule deleted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
data/spaces holds 157k real user images that the private raiw-app retention
checks materialize here. The only thing keeping them out of a commit was an
untracked .gitignore inside the directory, which a fresh clone does not
have.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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>
The previous commit slipped past a red test: the pytest exit code was
swallowed by a pipe in the shell chain. This pins the test to
4c2763766dd1c8c212d64e01e1cc3f166243c47d.
Published via publish-photo-classify-hf.yml (run 34188279796) from the
photo-classify-freeze-2026-09-07 release: six-head provider.pt, model-side
receipt-gate.npz, updated card and operating point. Older lib versions
keep their own pinned revisions byte-for-byte.
Provider classes now name the GENERATOR that rendered the pixels, never
the brand. bytedance joins openai/google/muse-image as the shared
ByteDance lineage (Doubao and Jimeng render with one model family;
measured: separate heads cross-fire 32/22 at 3.5x mass, the surgical
union holds 83.9% on the frozen test cell while openai/google/meta/no_ai
stay byte-identical to run1). tc260 stops being a public value: its head
remains as the group veto for the rest of China's generators (without
it, 207/379 China test rows would be falsely named openai or
muse-image), and the loader tolerates provider snapshots that predate
bytedance. The receipt gate moves model-side: stable-name artifact
receipt-gate.npz carries its threshold, head and threshold always load
from one file, and the publish script stages the stable gate from the
weights source. Microsoft stays metadata-only: 144 of its 253 bank rows
name an OpenAI model as their C2PA softwareAgent and none names a
Microsoft renderer.
pre-commit: 1) maintain.sh - exit 1 (uv-secure: lightning 2.6.5 via
trustmark, PYSEC-2026-3624 no fix released; per docs/development.md the
core checks ran separately: ruff clean, pyright 0 errors, 2059 passed
3 skipped); 2) /simplify - single-pass four angles, clean, one noted
skip (gate-test npz staging duplication); 3) docs sync - grepped
bytedance/receipt-gate.npz/provider values over README, docs, skill,
rules: no stale references; 4) CLAUDE.md - improver: no changes,
revise: no additions (learnings live in canonical docs)
The rule used globs, which Claude Code ignores, so it loaded in every
session. CLAUDE.md keeps the fact that this gate does not pass
--ignore-unfixed and routes the lightning triage to docs/development.md.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three withheld zero-face carriers, all confirmed zero-face with the same YuNet
detector the adaptive arms gate on, first cleared at 0.045 / 0.06 / 0.11. The
zero-face operating point is 0.11 + (0.11 - 0.045) = 0.175, which the shipped
0.20 already covers, so that floor now rests on both content classes rather than
only the face-bearing carriers it was derived from.
The content split this cohort kept suggesting does not survive the measurement:
the two classes differ by 0.025 while the spread WITHIN each is 0.065 and
0.0625, so a face split would key on a variable explaining about a quarter of
the variation it leaves behind.
The methodological point is the durable half. The fixture-only view of zero-face
OpenAI content spans 0.015 of boundary; the real carriers span 0.065, four times
wider. A narrow fixture spread yields a small worst-clean-plus-one-spread margin
and a false impression of homogeneity, and that impression is what made a split
look justified twice.
Every verdict is the public verifier's separate SynthID line with Content
Credentials reported not detected alongside, over RGB-identical metadata-stripped
positive controls.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ETI scoring program applies median blur and JPEG before decoding, so an
attack only wins if the watermark stays dead under ordinary handling. Our
removal paths are structural, so no driving question exists today; the note
records the hour-sized handling arm over removed-state artifacts as the
follow-up if removal durability under platform re-encoding ever becomes a
real question. Also records that participant attack code was never
published.
Verified against primary sources: the ETI Competition Data (NeurIPS 2024)
carries no license on the dataset card or in the evaluation repository and
stays off limits without organizer permission; the W-Bench dataset (ICLR
2025) is MIT while the VINE code is NTUITIVE non-commercial, so a profile
is buildable on our kernel without the VINE code. Also corrects two stale
internal notes: ETI attacked outputs are in the release, and W-Bench holds
10,000 instances, not 15k.
Extend the development-only benchmark family from images to audio and
video, and close four research directions from the watermark-landscape
map with local, revision-pinned evidence.
Benchmark schema: media_type audio and video rows, audioseal and
videoseal adapters with media-checked adapter binding, sample-domain
audio fidelity (SNR with unbounded_identical), frame-domain video
fidelity (mean PSNR, changed-frame fraction), and per-frame temporal
evidence in videoseal detection records. The report accepts all three
media types and carries SNR columns.
Audio: shared pinned AudioSeal oracle, synthetic and system-voice
speech cohorts with matched negatives, codec, noise, removed, and
forged arms, and the provenance experiment proving visual-only video
cleaning leaves the audio bitstream and watermark verdict invariant.
Video: TorchScript-only VideoSeal oracle (the pip package is unusable
on macOS arm64 and its loader resolves paths relative to cwd), video
cohort with crf/scale/fps attacks and four-state arms, temporal
evaluation measuring the crf decay curve, the frame-aggregation matrix
(computed locally after finding the TorchScript build ignores the
aggregation argument), and real provider clips as carriers.
Forgery: double-embedding study showing the last writer wins completely
under both oracles, scoped remover-trace probe, and the forged/
removed cohort arms encoding each scheme's correct expected verdict
(presence rule for audioseal, message rule for videoseal).
C2PA resolution: measured the five vendors' resolver contracts and the
C2PA 2.2 18.10.5 privacy gradient; product decision recorded that this
tool never resolves over the network. A registry guard pins the
published resolution-API set.
Gate: ruff and pyright src/ clean, 2114 passed / 3 skipped; maintain.sh
stops only on the known unfixed lightning 2.6.5 CVEs, pre-existing.
The test monkeypatched huggingface_hub.snapshot_download by string, which
imports the real module. huggingface-hub rides the classify extra, not
the dev sync, so the CI matrix failed with ModuleNotFoundError on every
platform while the shared checkout venv hid the gap. Insert a stub into
sys.modules instead: the seam under test is classify's request, not the
hub client.
The clawhub job in distribute.yml compares the SKILL.md version with
the published one on every GitHub Release and submits an update when
they differ. Gated on the CLAWHUB_TOKEN secret: without it the job
skips with a notice, so the workflow lands safely before the secret
exists. A submitted update waits for ClawHub security scans, so a
green job means submitted, not listed.
The runtime's _weights_dir resolves the Hub snapshot offline through an
inline allow_patterns list, so a deployment that pre-caches the snapshot
for HF_HUB_OFFLINE=1 had to re-list the files by hand and silently
drifted when a release added one: the offline resolution then failed on
a four-fifths-present cache even though every missing piece had its own
fallback. Export the exact runtime request list as one public name, use
it in _weights_dir, and pin the seam with a test that captures the
snapshot_download call. Document the contract in photo-classify.md and
module-internals.md.
Issue #98. cv2's encoders write no container metadata, so every pixel-path
output (all, visible, invisible, erase) came back without its colour profile
and orientation tag, even with --keep-metadata.
imwrite now takes display_tags_from, the file whose decode produced the
pixels, and restores the two display tags into the re-encoded output: PNG and
JPEG by splicing iCCP/eXIf chunks and APP1/APP2 segments into the encoded
bytes, WebP by a lossless Pillow re-save (libwebp hides hand-spliced chunks
from readers without a VP8X header), HEIF through the save call itself.
Orientation is re-tagged only when the raster still has the source's stored
dimensions: cv2 rotates JPEG and (build-dependent) PNG decodes under
IMREAD_COLOR but never IMREAD_UNCHANGED, which is what the pixel paths read
with, so the decision is made against the raster's own shape and cannot
double-rotate.
The default metadata strip now preserves what the restore put back: the PIL
path forwards the profile and a scrubbed EXIF (orientation included) for PNG
and WebP outputs, the 16-bit chunk walker re-emits eXIf scrubbed instead of
dropping it wholesale, and --remove-all actually drops the ICC profile on
every format (Pillow's saver fallback kept it alive, contradicting the
documented "removed by --remove-all").
Mirror and 180-degree orientations (2, 3, 4) stay untagged: no cheap signal
distinguishes a rotated decode from a stored one for them.
ComposioHQ accepted a submission with no adoption bar (PR 1841);
VoltAgent lists reject brand-new skills, and the openclaw list indexes
ClawHub entries only. Both re-attempts are deferred with their
re-entry criteria.
Three invariants the deterministic suite did not pin: the version
triple (SKILL.md, plugin.json, marketplace.json), the 500-line SKILL.md
budget, and probe.py MIN_CLI_VERSION never exceeding the package
version. skill.yml gives skill-only changes a seconds-fast gate on top
of the full Tests workflow.
CLI-reachable through invisible --text-manifest, present since v0.27.0,
so no MIN_CLI_VERSION change. Skill version 1.0.2 across SKILL.md,
plugin.json, and marketplace.json. The receipt-abstention wording for
classify is deferred to the 0.38.0 release change, where it belongs with
the MIN_CLI_VERSION raise.
ffc46db5 carries receipt-gate-2026-09-02.npz and the receipt_gate
operating-point entry, so fresh classify installs load the gate from the
model snapshot; the package asset remains the fallback for pre-gate
weights directories.
The gate head is fitted on the freeze CLIP-L-ft embedding space, so it
belongs with the model: _load_receipt_gate now prefers
receipt-gate-2026-09-02.npz from the Hub snapshot or the
RAIW_CLASSIFY_WEIGHTS directory, with the package asset kept as the
fallback for weights frozen before the gate existed. Card mode of the
publish workflow now uploads the gate alongside the README and the
operating point, and the snapshot allow-pattern includes it.
Windows has no execute bit, so asserting one on the sandbox CLI copy failed both
Windows jobs while every other platform passed. The shim is launched through the
interpreter there anyway, so the assertion is POSIX-only.
The subprocess env is now overlaid on the real one rather than replacing it.
That was not the failure -- the hand-built env happened to work -- but a PATH of
`/usr/bin:/bin` and no SystemRoot is not something to leave in a test that CI
runs on Windows.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>