Commit Graph
172 Commits
Author SHA1 Message Date
Victor Kuznetsov 33f748b32a Record VACE and ROSE video inpainting results 2026-09-28 10:54:19 -07:00
Victor KuznetsovandClaude Opus 5.5 742a0dccab Align the remaining klein and color-restoration wording with the results
module-internals still called FLUX.2 klein pending; the sweep still counted
three inconclusive Gemini rows where only one was an explicit tool verdict,
and the removal page stated a Google chroma leak the data only warns of.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:24:59 -07:00
Victor KuznetsovandClaude Opus 5.5 f855c4700f Merge origin/main into docs/library-research-landscape
Main's claim_generator_platform and c2pa_vendor_platform now use the
branch's whole-word registry match, which replaces
claim_generator_word_platform. The branch's provenance veto covers every
video mark and made main's Veo-over-Sora override unreachable, so the
override is removed. Main's credential rule carries into the veto: an
invalid credential vetoes nothing. Provenance that confirms the mark's
own vendor also vetoes nothing. Over 78 local videos with a C2PA AI
claim, the only verdict changes against main are Kling/Hailuo false
positives on Veo and FLUX clips that the veto now removes. C2PA verdicts
over 1,379 files are unchanged against the pre-merge branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:52:29 -07:00
Victor KuznetsovandClaude Opus 5.5 5a0f771ed7 Close the remaining raw-byte identity scans and unify two rules
- A decoded manifest no longer takes its generator from a raw
  claim_generator CBOR value or a soft binding from raw bytes. Device tokens
  (NIKON, Pixel Camera, sony.sig) stay a byte scan, since the decoded strings
  do not carry them, but read the manifest store: an EXIF Make beside an
  unrelated AI manifest is not a verified capture. The source-kind scan keeps
  the whole buffer because it also reads IPTC digitalSourceType in XMP.
- The byte fallback's c2pa.ai-disclosure kind now uses the structured rule:
  human_validated beside prompt_guided is a generation, not an enhancement.
- Wan and Yuanbao share BottomRightAnchoredEngine instead of two copies of
  the corner gate. The Yuanbao anchor test shifted the mark outside the locate
  window, so it passed with or without the gate; it now shifts it inside.

Verdicts over 1,379 C2PA files, 468 fixture and capture files, and Wan and
Yuanbao detections over 285 images are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 22:19:30 -07:00
Victor KuznetsovandClaude Opus 5.5 509ce633a3 Judge decoded C2PA manifests on their decoded strings alone
Extend the whole-word rule to every identity lookup. Once the reader has
decoded a manifest, no identity is re-derived from its raw bytes: not the
signer, not a signer-platform token, not the AI-tool fallback for the
generator, and not the SynthID vendor inference, in identify and in
metadata.synthid_source alike. The byte scans read the manifest store only
when the reader could not open it.

Claim-generator tokens match as whole words through one shared
claim_generator_word_platform (suno no longer matches Sunoco), for images
and video alike.

The verdict now reads SynthID from the decoded C2PA info when the metadata
dict lacks it; three synthetic Google Photos tests had relied on the byte
fallback for that.

Verdicts over 1,379 C2PA files and 468 fixture and capture files are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:19:13 -07:00
Victor KuznetsovandClaude Opus 5.5 b02eb12cb2 Match registry tokens as whole words in decoded manifest strings
Registry tokens were raw substrings, so the Canva token matched the "Nova
Canvas" agent of an Amazon Bedrock image. Raw manifest bytes cannot take a
word-boundary rule: across the 1,379 C2PA files in the local corpus, 374 of
37,325 store matches had a letter or digit beside them, nearly all CBOR text
headers and DER tags. Decoded strings have no such framing.

- Match signer, claim-generator, agent and video-marker strings with
  registry_word_matches.
- When the reader decoded the manifest, never re-derive the signer from raw
  bytes: an unregistered signer stays unknown. Bytes decide only for
  manifests the reader cannot open.
- Add fal's signer "Features & Labels"; its attribution had relied on the byte
  fallback finding the "fal-ai" generator prefix.

Verdicts over 468 images and 365 videos are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:38:35 -07:00
Victor KuznetsovandClaude Opus 5.5 fb92c7dbc8 Attribute Amazon Bedrock C2PA and scope the signer fallback scan
Nova Canvas images published in aws-samples were reported as Canva: with no
Amazon row, the byte fallback matched the Canva token inside the "Nova
Canvas" software agent. Add an Amazon Web Services row ahead of Canva, which
also names Nova Reel video.

When the reader cannot open a manifest, scan for signers in the C2PA store
the container locates (JPEG APP11, PNG caBX) instead of the whole metadata
region. A vivo X300 camera capture was labeled "C2PA signer: Adobe" from its
XMP toolkit string. The SynthID provenance scan reads the same store.

Adds the Nova Canvas and Nova Reel samples as MIT-0 fixtures and records the
public-sample search for the other conformance-list signers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:21:13 -07:00
Victor KuznetsovandClaude Opus 5.5 7ba07869d2 Add paid-service captures, aggregator attribution, and provenance vetoes
Collect provider samples from Higgsfield, Runway and Dreamina plus Google
Photos, Gemini, Grok and YouTube re-encodes into data/captures/2026-09 with
a hash-checked manifest, and use them to fix attribution and false positives:

- Attribute aggregator outputs: Higgsfield job metadata, Dreamina's
  re-signed manifests, Runway's own C2PA signer, TC260 video producers.
- Veto any visible video mark when a valid C2PA claim names another vendor
  (a Gemini Omni clip read as Sora on steam), and gate Kling and Hailuo
  matches on edge, anchor and white-label evidence.
- Veto the Gemini sparkle when trusted provenance names another vendor.
- Report SynthID as present for Google Photos AI edits: Google's checker
  found it on all four measured edits, though manifests record no action.
- Add Vidu video and Wan image marks, TC260 audio placements, and record
  the AIGC key in metadata records.
- Document the research sweep, the Dreamina badge decision, and verified
  Google statements on SynthID in Photos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 14:32:53 -07:00
Victor Kuznetsov d25cada76b Export calibrated image source providers 2026-09-25 14:38:04 -07:00
Victor Kuznetsov b1f15818d7 Add pinned OpenAI and Google image source classifier 2026-09-25 14:23:01 -07:00
Victor KuznetsovandClaude Opus 5.5 1dc70df289 Upgrade to OpenCV 5 with frozen Hershey templates and tighten video marks
- Lock OpenCV 5 and cap NumPy below 2.4 through uv constraint-dependencies so
  PaddleX 3.7 keeps resolving; Dependabot ignores mirror the cap.
- OpenCV 5 draws Hershey putText glyphs differently, so the Dola and Kling
  video templates ship as committed OpenCV 4 renders with a recipe script, and
  the OpenArt alpha recipe now refuses any OpenCV but 4.x.
- Break Sora/Veo cross-matches in favor of Veo under valid Google AI-video
  provenance, and require the full Sora mascot shape for mascot-only matches.
- Let the Doubao engine detect marks tinted by saturated backgrounds.
- Share C2PA claim-generator, credential-level and vendor-platform helpers,
  JPEG suffixes and the DCT basis instead of per-module copies.
- Log model download failures, document the optional GITHUB_TOKEN, mark the
  photo and source classifier model cards archived, and refresh the lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:19:00 -07:00
Victor Kuznetsov be8f24c7cb Raise OpenAI Qwen strength floor 2026-09-21 23:02:49 -07:00
Victor KuznetsovandClaude Sonnet 5 83be3a8926 Add generic bare "AI生成" text-mark detector (brand-less TC260 fallback)
Every existing text-mark engine (Doubao, Jimeng, Qwen, Baidu, Kling,
Yuanbao) is tuned to one vendor's exact wordmark silhouette, so none of
them match a bare "AI生成" strip with no brand name in front of it.
Confirmed on raiw-app production: a free `visible` run left a bottom-right
"AI生成" watermark completely unremoved because no detector fired.

Research found the wording is not tied to one dominant generator: vivo's
own support documentation confirms its Gallery stamps a bare "AI生成"
label after AI消除/AI扩图/大片模式 editing, and independent reporting
documents the same watermark on Xiaomi Gallery's AI-edit output. Since
the label is a GB 45438-2025/TC260 compliance stamp rather than one
vendor's brand mark, this adds one generic fallback (`generic_ai_label`)
instead of another per-OEM tuned config.

The detection silhouette is font-rendered (no logo element to capture)
via the shared scripts/render_vendor_silhouettes.py pipeline already
used for Qwen/Baidu/Kling/Yuanbao's own text-only marks. Calibration is
synthetic-only (no real captured generator screenshot was available);
the module docstring and DETECT_NCC_THRESHOLD comment carry that caveat
explicitly and this should be recalibrated once real captures exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 22:01:10 -07:00
Victor KuznetsovandClaude Sonnet 5 9d29d2c777 Add OpenArt visible watermark detection and removal
OpenArt.ai stamps free-plan generations with a semi-transparent white
"OpenArt" wordmark (bowtie/infinity icon + brand name) placed near the
CENTER of the frame rather than in a corner. Confirmed from a customer-
reported raiw-app production case where the mark went completely
undetected and unremoved, with no C2PA/EXIF/TC260 signal for identify
to fall back on.

- Add a new "cc" (frame-center) corner mode to the shared
  TextMarkConfig/TextMarkEngine base, alongside the existing
  corner/edge anchors.
- Add openart_engine.py, following the existing text-mark engine
  pattern. No real capture exists (OpenArt requires an account, out of
  scope to create), so the bundled alpha asset is a procedural
  reconstruction of the public logo and the NCC threshold is an
  explicitly-labeled provisional guess, not a measured calibration.
- Register the mark in watermark_registry.py, which auto-derives
  identify's platform attribution.
- Add tests/test_openart_engine.py (synthetic composites only) plus
  registry/identify test coverage, and document the mark and its
  calibration caveats in README.md, docs/supported-signals.md,
  docs/module-internals.md, and the skill's commands.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 21:51:46 -07:00
Victor KuznetsovandClaude Sonnet 5 7a6491fdc1 Document Gemini sparkle decorative-glyph false positive, add observability
A decorative sparkle/glint glyph in stylized typography (e.g. a book-cover
title) can clear the visible Gemini sparkle's false-positive gate at
confidence just under _SPARKLE_FP_CONF, since it shares the same bright,
near-white, sharp four-point signature the gate uses to recognize a genuine
sparkle. Confirmed against a raiw-app production incident (2026-08-27) where
this caused the removal step to permanently smudge unrelated cover art.

Investigated tightening _SPARKLE_FP_CONF and the margin/gradient/saturation
checks (plus a prototyped local edge-density signal); each was disproved by
a constructed counter-example showing a genuine weak Gemini sparkle over a
noisy/textured photo background lands in the same confidence band with the
same signature, so no safe targeted fix exists without a real labeled
corpus. No detection/removal behavior changed.

Adds DEBUG logging at the exact FP-gate bypass path for future calibration,
a regression test (TestDecorativeGlyphFalsePositive) pinning the confirmed
false positive and the blocking counter-example, and a docs record of the
finding in the Gemini sparkle section of module-internals.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 21:41:59 -07:00
Victor Kuznetsov c7021b900b Add source pipeline classifier runtime 2026-09-15 23:17:48 -07:00
Victor Kuznetsov 8ce8bf14da Document GPT Image 2.5 compatibility 2026-09-15 21:32:46 -07:00
Victor Kuznetsov 380820fa7e Add SDXL verified-text restoration 2026-09-15 19:20:37 -07:00
Victor Kuznetsov a385aab433 Calibrate provider-specific invisible removal profiles 2026-09-15 16:38:17 -07:00
Victor Kuznetsov b5cd16aef0 Add local Microsoft InvisMark payload disruption 2026-09-14 12:07:00 -07:00
Victor Kuznetsov bf63e8e187 Attribute discovered C2PA signers 2026-09-14 11:51:19 -07:00
Victor Kuznetsov c4edc2820d Expand provenance metadata discovery 2026-09-12 13:36:46 -07:00
Victor Kuznetsov df94f2c908 Release 0.40.1 with Qwen symbol false-positive fix 2026-09-11 10:55:28 -07:00
Victor Kuznetsov b03a65bcb3 Release 0.40.0 with Qwen symbol, ONNX classify, identify attribution 2026-09-10 23:04:58 -07:00
Victor Kuznetsov f2f840197e Stop attributing shared AI labels to vendors 2026-09-10 21:08:18 -07:00
Victor Kuznetsov 242d78957b Pin published ONNX classifier snapshot 2026-09-10 20:07:33 -07:00
Victor Kuznetsov 78426aeef7 Add FP32 ONNX photo classifier backend 2026-09-10 19:31:24 -07:00
Victor Kuznetsov c903346a6b Support Qwen Create symbol watermark 2026-09-10 17:36:26 -07:00
Victor Kuznetsov 7cf067d3a5 Separate TC260 marks by manufacturer 2026-09-10 17:11:26 -07:00
Victor Kuznetsov 15cae6fc91 Speed up CLIP classifier cold start 2026-09-10 16:45:04 -07:00
Victor Kuznetsov 96b8ab9ae2 Let the HEIF container, not the blanked tag, decide the orientation carry
pillow-heif's opener rewrites the EXIF orientation to 1 and stashes the real
value in info["original_orientation"], while libheif turns the raster on decode
exactly when the container declares an effective irot/imir transform. A camera
HEIC (stored raster, EXIF-only rotation) and a re-encoded one (rotation baked
as irot) both decode with Image.size matching the raster and the tag blanked,
so _read_display_tags dropped the turn for both (issue #105): a camera HEIC
went through erase and came out sideways with nothing on it saying so.

For HEIF the caller's orientation_applied claim is now ignored the way it is
for TIFF, and the container decides: isobmff.heif_transform_applied scans
meta/iprp/ipco for an irot with a non-zero angle or any imir, the orientation
comes from original_orientation, and a transform-bearing file drops the tag.
AVIF keeps the generic path: this plugin build neither blanks its tag nor
applies the transform there, and a camera-style AVIF's orientation stays
unreachable from Pillow (recorded in known-limitations).

Tests build the camera fixture without exiftool: a pillow-heif-written file
with its irot angle neutralized to the identity behaves like the reporter's
exiftool-built camera file. Mutation-checked in both directions: forcing the
detector either way fails exactly the tests whose property broke.

pre-commit: 1) maintain.sh - exit 2 at the uv-secure gate, the three triaged
no-fix advisories in docs/development.md (rechecked 2026-09-09: accelerate
1.15.0 and lightning 2.6.5 still carry no fix); ruff check+format clean,
pyright src/ 0 errors, 2368 passed 3 skipped run separately; 2) /simplify -
single pass, no fan-out available, one duplicate test helper inlined, no
other findings; 3) docs sync - heif_transform_applied, original_orientation,
irot, imir live only in module-internals.md and known-limitations.md, both
updated, no other refs; 4) CLAUDE.md - audited against the structure rule,
no additions; revise-claude-md: no CLAUDE.md changes
2026-09-09 18:02:05 -07:00
Victor Kuznetsov 003dabfae4 Let the TIFF geometry override a caller's raw-decode claim
Both readers in the imread stack apply the TIFF orientation tag (cv2's
libtiff path under IMREAD_UNCHANGED too, and Pillow's TIFF plugin,
identically), so the visible path's blanket orientation_applied=False
carried the tag onto an already-turned raster. _read_display_tags now
ignores the explicit claim for TIFF and decides on the IFD's stored size,
which also keeps a hypothetical non-turning build correct: a stored-shape
raster still carries the tag. Guarded at the api seam, not just imwrite.

pre-commit: 1) maintain.sh - exit 2 at the uv-secure gate, the three
triaged no-fix advisories in docs/development.md (rechecked 2026-09-08);
ruff check+format clean, pyright src/ 0 errors, 2363 passed 3 skipped
run separately; 2) /simplify - single pass, no fan-out available, nothing
to fix (api-state plumbing rejected as disproportionate); 3) docs sync -
identifiers live only in docs/module-internals.md, updated, no other
refs; 4) CLAUDE.md - audited against the structure rule, no additions,
revise-claude-md: no additions
2026-09-09 12:56:14 -07:00
Victor Kuznetsov 36fed0594e Fix sharpening quantization and cross-platform regression tests
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.
2026-09-08 19:25:44 -07:00
Victor Kuznetsov 5c6588b3ef Fix output preservation, research validation, and documentation drift
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.
2026-09-08 19:07:10 -07:00
Victor Kuznetsov 56afcab241 Merge feat/model-freeze: generator taxonomy, model-side receipt gate
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).
2026-09-08 14:18:04 -07:00
Victor Kuznetsov 3daca46589 Detect and remove LiblibAI compact top-left pill 2026-09-08 13:37:07 -07:00
Victor Kuznetsov 15f5fee7c3 Add unified provider oracle tooling 2026-09-08 13:26:43 -07:00
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
Victor Kuznetsov 8562c457a4 Ship generator taxonomy: bytedance class, model-side receipt gate
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)
2026-09-07 21:13:48 -07:00
Victor Kuznetsov b2496134c2 Add margin to the explicit Chroma OpenAI floor 2026-09-07 14:15:57 -07:00
Victor Kuznetsov 723f2949ec Route OpenAI auto removal through Qwen 2026-09-07 14:01:17 -07:00
Victor Kuznetsov 7ddd2097bd Export WEIGHTS_ALLOW_PATTERNS for offline pre-caches
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.
2026-09-07 11:31:08 -07:00
Victor Kuznetsov 0d6667cf22 Separate runtime actions from development provenance checks 2026-09-06 20:18:47 -07:00
Victor Kuznetsov 646f72534b Carry the ICC profile and EXIF orientation across re-encodes
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.
2026-09-06 14:41:19 -07:00
Victor Kuznetsov efdbfa0598 Add real watermark fixtures and expand provider coverage 2026-09-05 13:12:58 -07:00
Diego 9f7b707016 Preserve 16-bit images through fill and metadata stripping (#101)
Keep alpha bit-exact, make remove-all drop iCCP, and bound MI-GAN conversion and PNG chunk-copy overhead.
2026-09-05 13:11:16 -07:00
Diego 697e11f2ab Report unsupported global CPU offload profiles (#104)
Handle unresolved auto preload through its Qwen fallback and avoid a false warning.
2026-09-05 12:30:00 -07:00
Diego 507d7c43a3 Run adaptive polish before the humanizer (#102)
Correct the postprocessing order documentation and simplify its regression coverage.
2026-09-05 12:10:17 -07:00
Victor Kuznetsov 5b52782f01 Move the receipt gate to the model side
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.
2026-09-05 11:51:02 -07:00
Victor Kuznetsov 0761937d60 Improve Samsung detector recall on textured images 2026-09-05 11:51:02 -07:00