Review-round hardening of canonical admission:
- passthrough now requires a single-frame source free of EXIF/XMP/IPTC
metadata, so location/device metadata never enters durable storage and
stored dimensions always describe the perceived pixels; animated WebP joins
GIF on the always-re-encode path (first frame only)
- SourceImageInfo records orientation-applied dimensions, keeping source and
stored raster on shared axes for coordinate mapping
- validateImage runs a canonical-encoding dry run, so a validated batch can no
longer be refused mid-write by the byte target (no partial writes)
- read_image names per-axis multipliers when rounding splits the two ratios
and maps IMAGE_TOO_LARGE to actionable downscale guidance
READMEs (both languages) describe the wide source envelope, the canonical
encoding and its fixed encoder parameters, and read_image's downscale
envelope; tool/config catalogs regenerate for the new schema and Config
fields. The read-image-dimension scenario now pins the acceptance the old
2000px admission cap refused: the 2001x1 source is admitted and stored
byte-identically, so the fixture stays platform-independent.
The canonical ref serializes mediaType, width, height, bytes in the order the
pre-canonicalization store used, so existing session-log fixtures and logged
histories keep byte-identical reference JSON.
When the attachment store's canonical encoding shrinks the file on disk, the
read_image envelope names the original dimensions and the multiplier that
maps coordinates measured on the attached image back onto the file, and the
output schema carries sourceWidth/sourceHeight for programmatic callers.
Admission now validates a wide source envelope (32MiB, 100MP, 16384px per
side) and persists a canonical encoding instead of refusing large sources:
EXIF orientation baked in, metadata stripped, long edge downscaled to the
configured canonical target (default 2048px), PNG palette for alpha/PNG/GIF
sources and a fixed JPEG quality ladder (85/75/60/45) until the canonical
byte target holds (default 1MiB). In-budget PNG/JPEG/WebP passes through
byte-identically so equal sources keep deduplicating to the same content
address; GIF always re-encodes to the PNG of its first frame, pinning the
first-frame meaning providers apply. Encoder parameters are fixed by design;
only the canonical budget is deployment configuration.
AttachmentStore.saveImage now resolves SavedImageAttachment: the durable
reference paired with the submitted raster's intrinsic facts, so a store may
persist a canonical re-encoding while callers keep the source dimensions for
coordinate mapping. saveImages keeps returning refs; every fake store and the
cordis API catalog follow the new signature.
The documentation site deployed on every master push, with no reviewer and
no version check, while npm, PyPI, and the public source repository all
advance only at a release tag. The Pages site is reachable without
authentication, so a merge published documentation ahead of every artifact
readers could obtain.
docs-pages.yml now declares workflow_dispatch alone and verifies the ref
through the gate npm publication already runs, so the site and the npm
sequence share one definition of a released version.