RFC 0010 — Portable resource and package profile
Document status: proposed, with an executable experimental container subset. The. Canonical source.
reference implementation now provides stable assets, deterministic
nuif-package-0, explicit verified resolution and the package segment of
nuif:experiment:portable-package-resources. This RFC does not add image
rendering or general packaged-font conformance to profile 0. The orthogonal
nuif-png-rgba8-0 experiment now implements a narrow cross-decoder and CPU
image path. The nuif-opentype-static-single-0 experiment likewise implements
one narrow package/parser/policy baseline; broader image and font profiles still
have to satisfy their acceptance criteria.
Motivation
The current implementation serializes a semantic document as canonical text or CBOR. That is sufficient for profile-0 fixtures because images are unsupported and the one text font is an external pinned conformance input. It is not a portable authoring package: images, fonts, source correspondence and other resources have no common descriptor or delivery contract.
The draft serialization module previously called .nuif a package while
leaving its archive technology experimental. The roadmap then described
“package/assets” as complete for profile 0. Those statements conflict. This RFC
defines a candidate profile and restores the implementation gate.
The design must distinguish:
- stable semantic asset identity;
- identity of immutable resource bytes;
- a locator inside or outside a package;
- source and derivation provenance;
- semantic document hash;
- exact delivered-package hash.
Using one path, URL or hash for all six roles would break editing, offline portability or reproducibility.
Prior art and evidence
nuif:research:epub-ocf-package-container: OCF separates an abstract container from a constrained ZIP form, requires a manifest and identifies the media type in a fixed first uncompressed member.nuif:research:oci-resource-descriptors: OCI binds media type, size and digest, verifying cheap limits and bytes before content interpretation.nuif:research:content-addressed-versioning: immutable byte identity is not stable editable entity identity.nuif:research:png-image-preservation-and-decoding: original encoded image bytes and declared decode parameters are distinct from decoded caches.nuif:research:opentype-font-embedding-and-portability: reproducible text needs exact bytes, but redistribution policy must be explicit.nuif:research:penpot: the existing bounded adapter proves defensive ZIP handling but not this package layout or cross-writer determinism.
Proposed semantics
1. Encoding and extension names
.nuifidentifiesnuif-package-0, the portable package profile..nuif.cboridentifies bare canonicalnuif-cbor-0document bytes..nuif.jsonidentifies bare canonicalnuif-text-0document bytes.
During the alpha migration, readers MAY recognize historical bare documents
whose name ends in .nuif. Writers MUST emit the package for .nuif and MUST
use an explicit bare extension for new bare documents. Legacy recognition is
read-only compatibility and MUST NOT weaken canonical codec validation.
2. Resource identities
AssetId is the stable semantic identity referenced by document entities.
Replacing an asset’s bytes does not change AssetId; it changes the asset’s
bound ResourceDigest through a semantic operation.
ResourceDigest in package profile 0 is:
sha256:<64 lowercase hexadecimal digits>
It identifies exact encoded bytes. Implementations MUST verify declared size and digest before decoding the resource.
ResourceDescriptor contains:
digest ResourceDigest
size unsigned byte length
media_type normalized ASCII media type without a retrieval-dependent value
role source | authoring | derived | cache
locator embedded path, or explicit linked locator plus expected digest
derivation required for role=derived; absent for source/authoring/cache
The descriptor is immutable by digest. Metadata that changes interpretation of the bytes belongs in the semantic asset or a versioned decoder profile, not in an untracked package field.
3. Asset semantics
An Asset contains stable identity, kind, current resource digest, portability
policy and kind-specific semantic metadata. Initial kinds are image and
font; unknown future kinds follow extension-preservation rules.
An image asset records intrinsic dimensions and the decoder profile. An
ImagePaint refers to AssetId and records fit, crop, transform, sampling,
opacity and declared color conversion. Decoded RGBA and GPU textures are
deletable caches, never source resources.
The reference scene interns decoded RGBA by resource digest plus decoder profile and gives commands deterministic numeric surface handles. Its 64 MiB unique decoded-surface total is preflighted from bounded image metadata before inflation. Repeated asset instances therefore do not duplicate decoded pixels or descriptor strings.
A font asset records exact byte digest when available, media type, face or
collection index, names used for matching, axes, features, character coverage
and policy evidence. Text shaping continues to pin its execution inputs. An
optional stable text-to-font AssetId keeps the requested text hash distinct
from the effective resource hash: exact bindings require equality, substituted
bindings retain the request and select the asset resource, and unavailable
bindings select an asset with no resource.
Font portability policy is one of:
portable: exact bytes can be embedded for the declared package use;private_authoring: bytes may exist in a private workspace package but not a distributable portable package;linked: bytes are absent; locator and expected digest are explicit;substituted: another exact resource is used and fidelity identifies the substitution;unavailable: no usable bytes; fidelity identifies the consequence.
OpenType fsType is recorded policy evidence, not a complete legal conclusion.
4. Package members
nuif-package-0 is a ZIP archive with these members:
mimetype
manifest.cbor
document.cbor
blobs/sha256/<64 lowercase hexadecimal digits>
Optional correspondence, capture, report and cache records MAY be added only at paths registered by a later profile. Profile 0 package readers reject unregistered member paths instead of guessing their meaning.
mimetype is the first local-file member, stored without compression,
encryption or extra fields. Its exact ASCII bytes are:
application/nuif+zip
This media type is provisional until registration and MUST NOT be represented as IANA-registered.
manifest.cbor and document.cbor are canonical nuif-cbor-0. The manifest
declares profile/version, the semantic document descriptor, required
capabilities, assets, all resource descriptors and their roles. It does not
contain its own digest.
The required-capability set contains at most 256 identifiers of at most 128
ASCII bytes each. Structural readers validate and preserve those requirements.
Hosts use capability_report or require_capabilities with an explicitly
declared supported set before claiming full package support; missing
requirements are reported exactly. Structural decode alone is intentionally
available to inert inspection, preservation and extraction tools and is not a
semantic-support claim.
A structural SDK, CLI or editor that does not support every required capability
MUST keep the package read-only. It MAY validate, hash, extract the bare
document and copy the unchanged same-mode package, but it MUST NOT evaluate,
change document.cbor or change package mode while carrying capability
resources forward unless complete-set negotiation succeeds or a
capability-specific authoring profile explicitly detaches those resources. A
failed partial negotiation grants no authority. This prevents a
content-addressed sidecar from being silently bound to a document revision it
never validated.
Every embedded resource is stored at the path derived from its SHA-256 digest. The path is a locator. The manifest digest remains the identity and MUST match the bytes even if a future profile permits another physical layout.
5. Deterministic ZIP profile
The first profile uses stored members only. This deliberately trades archive size for cross-writer byte determinism and simple expansion limits. Images and fonts are usually already compressed; a later measured profile may add a fixed compression method without changing semantic hashes.
Writers MUST:
- emit
mimetypefirst, then every other member in bytewise ASCII path order; - use only the exact registered ASCII paths above;
- use ZIP method 0 (stored), no encryption, no data descriptors, no ZIP64 unless a later profile permits it, no archive/member comments and no extra fields;
- set the DOS timestamp to 1980-01-01 00:00:00;
- set a fixed creator/version and regular-file external attributes defined by the conformance fixture;
- precompute CRC-32 and sizes so local and central headers agree;
- emit no directory entries;
- emit one central-directory entry for each local member in the same order.
The manual writer and the independently implemented zip 8.6.0 writer now
produce identical fixture bytes with creator/version 0x030a, version-needed
10, regular-file attributes 0x81a40000 and the rules above. These values are
fixed for the experimental nuif-package-0 implementation. Standards-track
stability still requires cross-platform and externally maintained reproduction.
Readers MUST reject duplicate decoded names, backslashes, absolute paths, dot-segments, empty segments, non-ASCII paths, symlinks, directories, split or spanned archives, encryption, unsupported compression, inconsistent headers, undeclared blobs and declared embedded blobs that are absent.
6. External resolution
A portable package embeds every resource required to evaluate its declared profile. A linked/private authoring package may contain a linked locator, but:
- loading a document MUST NOT cause implicit network access;
- a resolver is an explicit caller-supplied capability;
- resolved bytes MUST match declared size and digest;
- redirects and authentication are resolver policy, never package authority;
- credentials, cookies and bearer tokens MUST NOT be stored in locators or provenance records;
- failure to resolve produces a typed fidelity/availability result.
Original URLs are provenance or retrieval hints, not resource identity.
7. Hashes
The semantic document hash remains SHA-256 of canonical document.cbor bytes.
It changes only when semantic document content changes.
The package hash is SHA-256 of the complete deterministic ZIP bytes. It proves the exact delivered artifact and changes when package-only records or caches change.
A resource digest is SHA-256 of exact resource bytes. An asset binding is semantic and therefore participates in the semantic document hash. Package locations and deletable caches do not.
Executable narrow image segment and broader proposal
nuif-png-rgba8-0 now executes the smallest unambiguous subset: bounded,
non-interlaced RGBA8; no ancillary metadata or one valid pre-image sRGB
intent; encoded samples interpreted as sRGB; straight decoded alpha; identity
decoder orientation; declared fit/crop, bounded forward affine transform,
nearest or fixed-bilinear sampling, opacity
and encoded-sRGB integer source-over. It rejects every other colour type,
bit-depth, colour signal, Exif/animation chunk and arbitrary metadata. Two
independent decoder libraries must agree on exact RGBA bytes. Exact rules and
non-claims are versioned in crates/nuif-media/PROFILE.md, and
cargo xtask gate-i-image emits its machine evidence.
The separately named nuif-png-basic-rgba8-1 decoder profile adds every
non-interlaced PNG colour/depth combination that can normalize to RGBA8 without
sample-precision loss. Image-paint transforms use
[a c tx; b d ty; 0 0 1] from crop-local source coordinates into the fitted
paint rectangle; the CPU reference inverse-samples pixel centers and rejects
singular or numerically unbounded matrices. Decoder and paint semantics remain
separate contracts even though Gate I exercises them together.
The broader PNG experiment remains separate. It must pin:
- accepted PNG conformance and ancillary chunks;
- decoder library/version or independent semantic rules;
- CICP/ICC/sRGB/gamma/chromaticity precedence and conflict policy;
- Exif orientation behavior;
- straight-alpha decoded representation and explicit premultiplication point;
- output color space, sampling and compositing;
- encoded bytes, dimensions, pixel count, decoded bytes, chunks and metadata limits;
- malformed-image and independent-decoder fixtures.
Animated PNG, JPEG, WebP, AVIF, video and SVG do not enter this profile by fallback. An adapter may freeze a selected animation/video frame as a derived resource and must report the transformation. SVG is imported through a safe declared adapter subset or retained as inert source; scripts and external resources never execute when a package opens.
Executable narrow font segment and broader proposal
nuif-opentype-static-single-0 accepts exact static TrueType-outline sfnt bytes
only under a declared portability policy. It requires face index zero,
canonically packed and checksummed tables, matching family names and exact
Unicode coverage, no variation axes, a matching fsType value, a non-empty
license expression and explicit embedding review. Package encode/decode and
resolved linked bytes run the same validation. The exact rules and non-claims
are in crates/nuif-font/PROFILE.md; cargo xtask gate-i-font compares Skrifa
0.46.2 behind NUIF-owned sfnt validation with a committed HarfBuzz 14.4.0
metadata capture for the pinned Ahem fixture.
The reference runtime now composes this accepted resource profile with HarfRust/Skrifa/Zeno: a package session registers exact embedded bytes, applies declared global OpenType features, uses shaped advances and face ascent for layout, lowers unhinted outlines and emits deterministic CPU pixels. A Tinos package is the blocking non-Ahem fixture. This is local implementation evidence; it does not make general OpenType or cross-platform raster claims.
This executable slice deliberately rejects TTC, CFF/CFF2, variable, color, bitmap, SVG and WOFF/WOFF2 fonts. Research assigns these to separate collection, variable-TrueType, CFF/CFF2, COLR-vector, bitmap/SVG-glyph and WOFF2 transport capabilities. Each broader font-resource profile must pin:
- parser and table/resource budgets;
- face/collection selection;
- axes, named instances and feature selection;
- coverage and shaping inputs;
- malformed-table fixtures;
- handling of
fsType, no-subsetting and bitmap-only flags; - policy outcomes for portable/private/linked/substituted/unavailable resources.
No profile may infer exact font identity from a family name or screenshot.
Compatibility and migration
Existing canonical document bytes and hashes remain valid. Packaging them does
not alter document.cbor or its semantic hash. Current .nuif raw fixtures are
readable during alpha through content detection; tools should rewrite them only
on explicit save/export and should report the transition.
The package layer belongs above nuif-codec: codecs own canonical bare
encodings, while the package implementation owns manifest/resource/ZIP rules.
The core owns asset/resource semantics. CLI, editor, WASM, FFI and process
adapters call the same package API and MUST NOT carry independent ZIP policy.
The reference nuif-wasm-api-0 binding exposes structural package load,
explicit manifest-capability negotiation and deterministic package export over
byte arrays. Its cross-surface gate requires both no-op and edited package bytes
to match the native SDK exactly and preserves an embedded capability resource
without interpreting it. The same gate rejects a semantic edit through a
structurally loaded requirement-bearing package before complete-set
authorization. This is the browser/plugin package transport; host object access
and capability execution remain separate adapters.
Security
The package is untrusted. Before acceptance, the profile requires calibrated limits for total archive bytes, member count, per-member bytes, total expanded bytes, descriptor count, image/font bytes and decoder allocations. Resource size and digest are verified before media parsing. Readers do not extract to a filesystem.
The executable allocation gate additionally requires package-to-session handoff to share immutable resource buffers. Its 8 MiB trial preserves the allocation pointer and permits at most 1 MiB of handoff allocator traffic and retained bookkeeping. A 1,024-instance image trial permits at most 8 MiB of scene-build allocator traffic and 4 MiB retained for one 1 MiB decoded surface. These are reference-CI regression ceilings rather than wire-format limits.
Package resources never execute by being present. Scripts, shaders, links and embedded metadata are inert unless a separately authorized sandboxed capability interprets them.
Conformance tests
nuif:experiment:portable-package-resources must prove:
- two independent writers produce identical bytes on the normative fixture;
- package write/read/write reaches a byte fixpoint;
- required capabilities are bounded identifiers and missing host support is returned as the exact deterministic requirement set;
- document hash is unchanged by package creation and deletable-cache changes;
- asset identity survives byte replacement while the resource/document hashes change as specified;
- missing, extra, duplicate, traversal, symlink, directory, encrypted, unsupported, mismatched-size and mismatched-digest cases fail atomically;
- no implicit external resolution occurs;
- boundary and one-over archive/resource cases pass measured limits.
The narrow PNG experiment and package experiment must pass before claiming
nuif-png-rgba8-0. The broader PNG and font experiments must pass before those
resource classes are claimed generally.
Rejected alternatives
- Keep
.nuifas ambiguous raw JSON/CBOR indefinitely: prevents reliable media identification and resource delivery. - Use paths or URLs as identity: moving a package or changing a CDN URL would change identity without changing bytes.
- Use content hashes as editable asset IDs: every image replacement would break semantic references and operation history.
- Store decoded RGBA instead of original images: loses source encoding, color metadata and efficient distribution.
- Embed every font found by a browser: local bytes may be inaccessible and redistribution may not be permitted.
- Permit ordinary ZIP/ZIP64/compression options: expands attack surface and prevents a simple first cross-writer byte profile.
- Use TAR: weak random access and no widely deployed first-member media-type convention for this use.
- Use OCI artifacts directly: descriptor ideas are valuable, but registry/image layering semantics are unnecessary for a single design package.
Unresolved questions
- Whether future packages add deterministic compression or rely on outer transport compression.
- Whether correspondence/capture/report records are canonical-adjacent members or separate linked artifacts.
- Media-type registration timing and final name.
- License-expression vocabulary beyond preserved evidence and user/admin policy.