Status: static contract implemented. Automated acceptance covers projection, admission, bounds, refusal, callback isolation, atomic export and independent Elixir/TypeScript readers. The site plan maps each requirement to its tests. Human verification is not a library gate. Producer semantics, geometry and native applications remain consumer-owned.
Owner: DocShell document bindings and presentation admission.
This extends DSH.01; it does not change the accepted v0.4.0 behavior or advertise a capability in a released DocShell 0.5.0 package.
Implemented entry points
DocShell.Presentation.ArtifactProfile, ArtifactBlock and ArtifactAdmission
provide explicit per-call profile validation and v2 presentation selection.
StaticExporter.export/1 accepts :artifact_options containing :profiles,
:manifests, :projections, :assets, :capabilities, :constraints and optional positive :limits.
Manifests and checked projections are keyed by original manifest digest; assets
use the existing Asset handoff. Producers retain their meaning and media checks.
The exporter attaches checked receipts in page metadata, admits only selected
variant assets and writes presentation-manifest.json separately from the
existing v1 site identity.
Constraint reader_mode is web by default;
explicit file mode rewrites validated local URLs to file-relative output paths.
The presentation manifest maps only selected artifact logical names to URLs.
In file mode those URLs resolve relative to presentation-manifest.json at
the output root; HTML URLs resolve relative to their own output files. Web mode
retains root-relative asset URLs. Renderer chrome assets do not enter this
artifact selection map.
Legacy calls and v1 capability/digest behavior retain their original path.
Schema/limit compatibility and reader parity use the automated suites in the plan. Publication alone does not establish those results.
Purpose and ownership
External illustrations, charts, and other bounded artifacts need exact references, accessible content, and presentation choices that reflect available runtimes. Adding a capability must not require a producer-specific branch in DocShell's AST walker. The first consumer is a technical illustration producer; a separate chart fixture tests the same contract with a second artifact type.
| Concern | Owner |
|---|---|
| Block identity, document anchors, captions, locale and reading order | DocShell |
| Artifact meaning, geometry, calculations and semantic subject validation | Artifact producer |
| Renderer implementation, interaction and observed output | Renderer package or native host |
| Retrieval, rights, disclosure, process supervision and publication | Host |
DocShell MUST NOT import the illustration producer, start its renderer, fetch an artifact URL, run downloaded code, or add browser/native dependencies to the core package. Artifact-producing workers run before document projection, under host ownership. A document can consume their completed artifacts without an installed producer runtime.
Inspected boundary
Source inspection on 2026-10-14 used DocShell
174321317affc6af53c25f982f6949ea8dc27d17:
DocShell.Astpreserves recursive JSON-safe nodes and extension fields.SiteProjection.Requirements.derive/1discovers a fixed list of feature tags.Renderer.Capabilityassociates one runtime list with all its states.Renderer.admit/3checks page requirements; a v1 optional fallback digest covers the feature ID and whole page content.Assetsupplies logical paths, media types and bytes;StaticExporterhashes those bytes and validates the completed local tree.Conformance.Surfacerecords document semantics, with no artifact-binding or per-block presentation observation.
Those existing APIs alone do not establish support for the extension. The new block, admission result, and renderer declarations require versioned fixtures; existing v1 declarations and digest rules remain unchanged.
Artifact block
DSH-A01 — Portable content. Use the
doc-shell-artifact-block/v1 record inside meta.artifact of an AST node whose
tag is artifact. Preserve the four existing AST keys. attrs.id is the
unique page anchor; content contains the complete safe fallback AST.
| Field | Required meaning |
|---|---|
schema_version | Exact block contract identifier |
profile, profile_digest | Namespaced producer profile and digest of its portable descriptor |
artifact_ref | Opaque exact producer identity; never interpreted as a fetch URL |
manifest_digest | SHA-256 of supplied original artifact-manifest bytes |
caption, description, locale | Document wording and its exact language |
bindings | Document anchor to exact producer subject references |
variants | Completed presentation records available to this document |
acceptable_states, essential | Permitted fallback/enhanced/connected states and essentialness |
fallback_digest | Checked digest of the block's complete fallback binding |
Every binding contains a unique anchor, opaque subject_ref, namespaced
subject_kind and subject_id. The producer validates membership in the
referenced artifact; DocShell validates uniqueness and document resolution.
Only textual AST attrs.id values declare document anchors. Arrays, objects,
numbers and booleans remain inert attributes; they cannot satisfy a binding
or create duplicate-anchor conflicts. An anchor can be outside its artifact
block if it exists as a textual document ID.
Triangle numbers, display labels and array positions cannot replace stable
subject IDs. Cross-document references include the qualified document ID.
A variant contains a unique id, exact profile/digest, state, media_type,
blob_digest, positive byte_length, logical asset name and runtime
requirements. Its caption/description and semantic coverage refer to the same
block. Variant bytes and manifests are supplied separately by the host; neither
filesystem paths nor credentials appear in the portable block.
Fallback content MUST retain required explanation, units, limitations and
warnings. A still image alone is insufficient when essential meaning requires
text. The primary artifact can be absent only for an optional block with a
complete verified fallback and an explicit unavailable presentation status.
Advertised variants cannot refer to absent bytes.
The void br element has no child content; placing text under it fails
admission because HTML readers would discard that text.
Extending capabilities
DSH-A02 — Explicit profiles. The host passes an immutable per-call set of profile descriptors and trusted validation adapters. Each descriptor contains its namespaced profile ID, revision, input-schema digest, subject vocabulary, supported variant media types, fallback contract and finite limits. Duplicate IDs with different digests fail. Profiles never arrive by automatic discovery, global registration, dependency import side effects or network lookup.
Every advertised variant media type and bound subject kind must occur in the
profile descriptor. Core checks these declarations before validate/2; returned
checked subjects must use the same vocabulary.
Descriptor subject vocabularies and media types are nonempty sets of unique
text values, each bounded to 4096 UTF-8 bytes. limits is a nonempty object
with nonempty bounded text keys and positive integer values no greater than
9,007,199,254,740,991. Their names and semantic enforcement remain producer-owned.
The packaged priv/contracts/artifact-contracts-v1.schema.json fixes the generic
structural records under named $defs. Runtime checks additionally enforce
UTF-8 byte limits, configured counts, unique IDs, path segments, cross-record
references, original-byte digests and deterministic admission. JSON Schema
maxLength counts characters and cannot replace these byte checks.
artifact-conformance-v1.json freezes synthetic chart/drawing profiles,
producer input schemas, original manifests/media, canonical content, receipts
and semantic observations. Its integer-only canonical bytes were produced by
an independent sorted compact JSON encoder. The listed producer-schema keywords
describe those fixtures' subset; they are not a core schema engine or an
external producer/native-reader qualification result.
DocShell.Presentation.ArtifactProfile provides
describe/0 and validate/2. describe/0 returns
the inert descriptor; validate/2 receives the block plus caller-supplied
manifest/subject projections and returns a checked projection or a located
tagged error. Callbacks contain no rendering or retrieval operation. The host
supplies modules explicitly; portable artifacts contain no module names.
The schema is producer-owned JSON Schema 2020-12 with a pinned supported subset:
- The adapter must refuse unsupported constructs rather than weaken validation.
- DocShell validates the generic envelope and checked callback result. It does not add a second producer validator or general schema engine.
- Exceptions, throws, exits, and malformed callback results become located errors.
Use the 2020-12 core and validation vocabularies as the declared source; supporting a subset is not full-schema conformance. Descriptor fixtures identify exactly which constructs are admitted.
DSH-A03 — Open feature namespace. A new supported profile derives its requirements through the same artifact block. Adding the chart fixture MUST require only its descriptor, adapter and renderer support; no core tag switch, producer-specific reference or new DocShell service is allowed.
Unknown optional profiles retain their opaque metadata and display verified safe fallback. Unknown essential profiles refuse before rendering. Unknown fields in this block's closed record fail; producer payload extensions use their own pinned schema.
State-specific presentation admission
DSH-A04 — Separate declarations. Specify
doc-shell-renderer-capabilities/v2 without retyping v1 fields. It retains the
site output modes hosted and static. Each feature lists exact profile and
schema digests, and presentation alternatives with an ID, output mode, state,
media types and their own runtime requirements. There is no inherited runtime
list shared by fallback and enhanced states.
The initial v2 runtime vocabulary is browser_js, live_transport and
native_host. An empty list requires none of them. A native artifact viewer
can consume the portable block outside the HTML site API; this does not invent
a native render_page/2 result type. Browser WASM that needs a script loader
declares browser_js; a WASM label cannot bypass that requirement.
DSH-A05 — Deterministic selection. The caller supplies ordered preferences for presentation IDs, an available-runtime set, a forbidden-runtime set and an output mode. Admission intersects the exact supported profiles, acceptable states, available variants and runtime constraints. Choose the first admitted preference, then the lexically first admitted presentation ID if no preferred ID matches. The result names block, variant, profile, runtime, selected state and any limitation.
Rendering consumes this result rather than renegotiating.
ArtifactBlock.verify_receipt/3 checks a previously admitted receipt against
the exact page/constraints/fallback digests, closed block/selection identity,
anchors, checked subject bindings and the selected feature/runtime declaration.
It runs no producer callbacks and chooses no replacement presentation. The
descriptor-set digest remains an opaque binding to the host's original
admission; verification does not authenticate a source or repeat producer
semantics. The renderer checks selected media bytes and implements their state.
Unavailable selections have no presentation_id and cannot retain a variant.
Static renderer context supplies artifact_assets, an inert JSON map of only
selected logical names to media_type and original base64 byte records.
Encoding occurs once after input admission. Renderer chrome continues to use
the existing asset URL map. This allows format/byte checks without file I/O or
network retrieval; it adds no artifact generation, producer lookup or process.
Runtime requirement arrays represent sets. Reordering either a variant's or a capability's runtime list must not change selection; receipts preserve the original variant record.
An empty available-runtime set with browser_js, live_transport and
native_host forbidden selects only script-free static output. static
always excludes connected output and live transport. A fallback does not
pretend an unavailable control succeeded. Required interactivity can refuse
an otherwise valid static export; the document author must deliberately allow
fallback where it preserves the requested task.
The host checks actual deployed/runtime capabilities. A renderer declaration is not proof that its output meets them. Tests inspect the emitted artifact closure and the observed presentation, including scripts and hidden fetches.
Identity, integrity and lifecycle
DSH-A06 — Separate identities. Page content includes block metadata and
fallback AST in its existing content digest. Define fallback_digest using
DocShell canonical JSON over block ID, profile/digest, artifact reference,
manifest digest, bindings, caption, description, locale and fallback AST.
Variants have separate raw-byte SHA-256 digests. Document canonicalization is
not RFC 8785 and cannot recompute a producer's semantic artifact identity.
Changing a scene, binding, variant bytes or fallback changes the corresponding document/presentation identity. It cannot rewrite the referenced composition, procedure, calculation or other producer identity. Selection receipts bind the exact page digest and caller presentation constraints. They contain no authorization grant or invented review status.
Export adds a separately versioned presentation manifest binding descriptor-set digest, capability manifest, selection constraints/receipts and selected asset closure. Do not redefine the existing site cohort digest to hide this extra identity. Replaying the same document with different runtime choices produces an explicitly different presentation binding. Legacy site manifests remain readable; new artifact consumers require this additional binding before use.
DSH-A07 — Local closure. Verify byte length and digest before exposing each variant; resolve logical names through the existing asset handoff. Export contains only the admitted dependency closure. Missing or altered fallback bytes, ambiguous references, mixed source bindings and duplicate assets fail before replacing the prior complete output.
A checksum is not source authentication. Host rights/disclosure decisions precede projection, including fallback text, descriptions, thumbnails and search entries.
Script-free output checks MIME essences case-insensitively, excluding parameters. They reject the browser-recognized JavaScript MIME aliases and active HTML/CSS before publication. Invocation options are validated even when the site has no pages.
Profiles accept only declared bounded media. SVG consumers apply a closed
element/attribute/URL policy and prohibit scripts, event handlers, external
resources and foreignObject in the script-free profile. Declared media type
alone is insufficient. Parsing/verification runs without network access; the
producer and renderer own format-specific validation.
DSH-A08 — Failure and recovery. Projection and export preserve the prior complete site on structural, integrity, callback or output failures.
A consumer-owned native reader preserves the previous permitted visual with its original binding and shows the successor failure; it cannot relabel old bytes as the requested scene.
An explicit optional unavailable result can display fallback. Revoked permission may prohibit displaying retained assets; the host enforces that decision without deleting historical identities implicitly.
Compatibility and bounds
DSH-A09 — Reader compatibility. doc-shell/v2 and doc-shell-site/v1
retain their current fields and meaning. Older readers see a safe unknown
directive's child content. A profile requiring verified artifact semantics
requires the new reader explicitly; old fallback display does not qualify it.
V1 capability manifests and page-wide fallback digests retain v1 admission. New per-block requirements and selection receipts use separate versioned records; unknown versions refuse without implicit conversion.
ArtifactLimits.new/1 supplies these finite defaults. Explicit positive
integer overrides may raise or lower them; unknown/duplicate keys and unlimited
sentinels refuse. Site page/depth ceilings and producer-specific bounds still
apply, with the lower applicable bound winning.
| Resource option | Default | Scope |
|---|---|---|
max_pages | 100,000 | Per batch |
max_page_bytes | 8 MiB | Native page content, checked as canonical JSON |
max_json_depth | 256 | Native JSON and original manifest container nesting |
max_json_values | 1,000,000 | Per native JSON value tree, including object keys |
max_ast_depth | 64 | Per page |
max_blocks | 256 | Per page |
max_bindings | 64 | Per block/checked subject list |
max_variants | 16 | Per block |
max_profiles | 128 | Per invocation |
max_descriptor_bytes | 64 KiB | Per descriptor |
max_manifests | 256 | Per invocation |
max_manifest_bytes | 1 MiB | Per original manifest |
max_projections | 256 | Per invocation |
max_projection_bytes | 1 MiB | Per supplied or returned checked projection |
max_admission_bytes | 8 MiB | Each capability/constraint document |
max_assets | 4,096 | Per invocation |
max_asset_bytes | 32 MiB | Per prepared asset/variant |
max_total_asset_bytes | 256 MiB | Per invocation |
ArtifactBlock.project_many/2 preflights every page, fallback binding and
advertised variant/supplied-manifest bytes before any profile callback.
Descriptors load once per batch; producer validation remains per block. Native
JSON bounds precede canonical encoding, and original manifest nesting is checked
before decoding. Callback descriptor/projection bounds are checked after the
callback returns and before its data is consumed. Checked subject anchors are
unique. This bounds admitted data, not arbitrary work inside trusted adapters.
Static export checks full page byte budgets before callbacks and after adding receipts. Selected output still passes existing file/site/output limits before publication. Failure retains the previous complete tree; resource settings cannot authorize additional reads or relax producer or disclosure policy.
Cross-platform preview and conformance
DSH-A10 — Preview parity. Preview consumes the same projected block and admission result as export. It shows caption, exact artifact/variant IDs, selected runtime/state, fallback, missing capabilities and semantic anchors. Its fixture mode includes light, dark, monochrome and enlarged views. It cannot mark observations as reviewed or accepted. Native readers and browser renderers may differ in layout but preserve these semantics.
Required automated vectors follow; the plan records their owning tests and package/browser evidence.
| Vector | Observable acceptance |
|---|---|
| DSH-A-V01 | Illustration and unrelated chart profiles load through the same core path; no producer import or core switch changes |
| DSH-A-V02 | Unknown optional content retains its fallback; unknown essential content, schema drift and duplicate profile IDs refuse |
| DSH-A-V03 | Altered manifest, bytes, length, anchor, locale or fallback refuses; prior export survives |
| DSH-A-V04 | Script-free preference chooses the static variant even when a JS enhancement exists; live-only output cannot pass static admission |
| DSH-A-V05 | Two concurrent hosts with different descriptors/runtime policy remain isolated; passive package load starts nothing |
| DSH-A-V06 | Independent Elixir and TypeScript readers preserve IDs, text, units, warnings, locale and limitations; missing anchors refuse |
| DSH-A-V07 | Unsafe SVG, external assets, traversal, case collisions and all limit boundaries refuse before publication |
| DSH-A-V08 | Preview and export share source digests and selected still state; print and JS-disabled offline browser retain complete fallback |
| DSH-A-V09 | Legacy collection/site/capability fixtures remain unchanged and readable; new requirements cannot be downgraded to legacy success |
| DSH-A-V10 | Three fixed seeds, at least 100 successful cases each, exercise ordering, round trips and admission against an independent small model |
Automated reader checks cover the generic document contract. Producer meaning, geometry and native application lifecycle stay with their owners. No browser screenshot or core test certifies a consumer's deployment.