> ## Documentation Index
> Fetch the complete documentation index at: https://invariant-cad.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Import and export

> Export meshes and exact exchange formats, and understand the current native-import boundary.

## Mesh export

All evaluated outputs can produce a mesh and shared mesh formats:

```ts theme={"system"}
const mesh = output.mesh();

const binaryStl = output.export("stl");       // Uint8Array
const asciiStl = output.export("stl-ascii");  // string
const obj = output.export("obj");             // string
```

`MeshData` contains flat typed arrays:

```ts theme={"system"}
interface MeshData {
  positions: Float32Array; // xyz triples
  indices: Uint32Array;    // triangle vertex indices
}
```

Each consecutive three indices forms one triangle. A reflected assembly
placement reverses triangle winding during mesh transformation so outward
orientation remains coherent.

## Tessellation options

Exact B-Rep output is tessellated on demand:

```ts theme={"system"}
const mesh = output.mesh({
  linearDeflection: 0.1,
  angularDeflection: 0.3,
  relative: false,
});
```

Options affect the extracted mesh, not the exact native shape. Manifold already
is a mesh representation and may ignore B-Rep-specific controls.

## STEP and BREP

Use OCCT:

```ts theme={"system"}
const step = output.export("step");
const brepText = output.export("brep");
const brepBinary = output.export("brep-binary");
```

Unsupported native formats throw `CadError` with an `EXPORT_UNSUPPORTED`
diagnostic because `export()` is a direct operation on a live output. Select a
compatible kernel before evaluation.

### Deterministic single-product STEP

<Note>
  This strong contract is implemented for the unreleased 0.2 line. The current
  0.1.1 npm package retains ordinary weak native STEP export.
</Note>

The bundled zero-override `createOcctKernel()` stock runtime advertises the
optional
`KERNEL_STEP_EXPORT_PROTOCOL_VERSION === 1` capability. This versioned
capability is stronger than `nativeExports` containing `"step"`:
`nativeExports` says only that the format can be written. Inspect the kernel's
capability object—not the kernel itself—before relying on the stronger
contract:

```ts theme={"system"}
const stepExport =
  inspectKernelStepExportCapabilities(kernel.capabilities);
```

A `"valid"` result contains the strong immutable snapshot; `"absent"` means
only weak STEP availability, while `"malformed"` means the advertised envelope
is invalid. `output.export("step")` without a second argument remains compatible
with weak native exporters; a supporting kernel uses deterministic defaults.
Passing any options object, including `{}`, requests the strong contract; an
absent or malformed `stepExport` envelope throws `CadError` with
`KERNEL_CAPABILITY_MISSING` instead of silently ignoring the request.

Explicit `wasm`, `moduleFactory`, and `attestedRuntime` initialization remains
on weak raw STEP export even when the supplied artifact is derived from stock
OCCT. InvariantCAD omits `stepExport` until that exact writer artifact has a
separate qualification boundary.

Pass deterministic metadata, cancellation, and a caller-specific output
ceiling through the STEP-only overload:

```ts theme={"system"}
const step = output.export("step", {
  metadata: {
    fileName: "mounting-plate.step",
    timestamp: "2026-07-26T12:00:00",
    productId: "PLATE-001",
    productName: "mounting-plate",
    productDescription: "Machined mounting plate",
  },
  signal,
  maxOutputBytes: 8 * 1024 * 1024,
});
```

Each metadata override is optional; every omitted field receives one of these
closed automatic defaults. `FILE_NAME` uses the design document name and its
timestamp is `1970-01-01T00:00:00`. A solid output uses its output alias for both
product ID and name, with an empty description. A part uses its authored part
number when present, otherwise its part-node ID, as the product ID; its
part-node ID is the product name, and its authored part description is the
product description.

An explicit timestamp must be a real calendar value in
`YYYY-MM-DDTHH:MM:SS` form. It remains deterministic because it is
caller-supplied input; changing it intentionally changes the bytes. The four
identity/description values accept Unicode scalar text. Apostrophes use STEP's
doubled-apostrophe convention. Literal backslashes and non-ASCII scalars are
encoded with ISO-10303-21 `\X2\...\X0\` or `\X4\...\X0\` directives as
required. Control characters and unpaired UTF-16 surrogates are rejected.
`fileName`, `productId`, and `productName` must be nonempty.

Invalid option structure, metadata text, calendar values, or the advertised
authored-metadata budget throw `CadError` with
`EXPORT_OPTIONS_INVALID`. Its `path` is a JSON Pointer relative to the
`StepExportOptions` input, such as `/metadata/timestamp` or
`/maxOutputBytes`. An already-aborted valid signal still throws `AbortError`;
low-level `kernel.exportShape(...)` calls retain their kernel-specific
validation exceptions.

Those defaults are a field-specific identity mapping, not a general metadata
pass-through. Root document `metadata`, arbitrary part `metadata`, material
identity, and the active configuration are omitted. A caller may explicitly
override a semantically corresponding supported STEP field, but protocol v1
provides no arbitrary key/value metadata channel. It does not silently fold
material data into the description.

The stock writer emits one AP214IS product. InvariantCAD then applies a
purpose-built structural ISO-10303-21 scanner and transformer to the exact
`FILE_NAME` and `PRODUCT` string fields; it does not use an unbounded regular
expression rewrite. The default output ceiling is 64 MiB and the combined
metadata ceiling is 64 KiB measured over the five resolved strings as
UTF-8. Part 21 escaping can expand that text; the expanded representation
counts toward the 64 MiB output ceiling. Input traversal, scan work, and entity
count also have fixed ceilings, and the scan checks cancellation.

The underlying stock native writer is synchronous and necessarily materializes
its original complete STEP string before InvariantCAD can apply post-write
limits or observe cancellation again. Metadata shape, content, timestamp, and
the authored UTF-8 budget are validated and encoded before that writer starts,
so known-invalid metadata never triggers native serialization. The writer
cannot be interrupted mid-call. After it returns, cancellation is checked
before, during, and after bounded scanning and before successful return.
`maxOutputBytes` limits the transformed bytes returned to the caller; it does
not cap the native writer's peak allocation or its original string. Isolate
untrusted or potentially pathological native work in a disposable worker or
process.

Byte equality is guaranteed only for the same backend shape representation,
options, resolved metadata, implementation, and exact runtime artifact. It
does not claim that geometrically equivalent B-Reps serialize identically,
make bytes portable as a cross-runtime cache identity, or canonicalize
third-party STEP. Exact aggregate STEP for assemblies and body-set results
remains unsupported; export retained single solid or part leaves explicitly.

## Save in Node.js

```ts theme={"system"}
import { writeFile } from "node:fs/promises";

await writeFile("part.stl", output.export("stl"));
await writeFile("part.step", output.export("step"));
```

## Send from a web server

```ts theme={"system"}
const bytes = output.export("step");

return new Response(bytes, {
  headers: {
    "Content-Type": "model/step",
    "Content-Disposition": 'attachment; filename="part.step"',
  },
});
```

Dispose the evaluated design after the response body has copied or taken
ownership of the returned detached bytes.

## Verified single-body import

<Note>
  This public workflow is implemented for the unreleased 0.2 line. It is not
  present in the current `invariantcad@0.1.1` npm package.
</Note>

The public imported-body boundary deliberately covers one exact solid, not the
broader staged product-document model:

```ts theme={"system"}
const created = createImportedBodyDocument("verified-housing", {
  id: "housing",
  resource: {
    id: "housingStep",
    digest,
    byteLength: stepBytes.byteLength,
    mediaType: "model/step",
    locations: ["memory:housing.step"],
  },
  format: "step",
  units: { mode: "from-file" },
});
```

`createImportedBodyDocument(...)` captures and validates the commitment but
does not read, fetch, or hash the bytes. The caller computes the SHA-256 digest
and exact byte length. `locations` are ordered hints passed to the resolver;
InvariantCAD never interprets them as files, URLs, or package paths.

The protocol-v1 media and unit policy is closed:

| Explicit format | Required media type        | Units                                                       |
| --------------- | -------------------------- | ----------------------------------------------------------- |
| `step`          | `model/step`               | `{ mode: "from-file" }`                                     |
| `brep`          | `text/plain`               | `{ mode: "declared", length: "mm" \| "cm" \| "m" \| "in" }` |
| `brep-binary`   | `application/octet-stream` | `{ mode: "declared", length: "mm" \| "cm" \| "m" \| "in" }` |

The explicit `format` selects the native reader. `mediaType` is committed
provenance and resolver context; it is never sniffed or used to infer the
format. Healing is fixed to `{ mode: "none" }`, and the strong kernel contract
must produce exactly one valid positive-volume solid. Multiple solids, shells,
loose topology, approximate conversion, and weak-import fallback are rejected.

Persist only the opaque document facade:

```ts theme={"system"}
const json = stringifyImportedBodyDocument(document);
const parsed = parseImportedBodyDocument(json, {
  limits: { maxDocumentBytes: 8 * 1024 * 1024 },
});
```

Parsing uses the bounded, duplicate-member-rejecting document boundary and
then admits only one resource, one imported-body node, and one direct solid
output. It does not publish or accept the broader product Document v7 grammar.

Evaluation requires an exact B-Rep evaluator with the strong document-body
import capability and a caller-supplied resolver:

```ts theme={"system"}
const result = await evaluator.evaluateImportedBody(document, {
  resolver: async (request) => {
    // Resolve by your own policy, then return bytes. InvariantCAD verifies
    // request.digest and request.byteLength before native parsing.
    return loadCommittedBytes(request);
  },
  resourceLimits: { maxResourceBytes: 32 * 1024 * 1024 },
  signal,
});
```

The resolver receives a frozen request containing the authored ID, digest,
length, media type, location hints, and optional signal. Resolution,
byte-length admission, and SHA-256 verification finish before
`importDocumentBody(...)` runs. A successful `EvaluatedImportedBody` exposes
exact B-Rep measurement, topology, tessellation, and capability-gated
single-solid STEP/BREP export. Dispose that result independently; it owns the
imported native shape but borrows the evaluator and kernel.

This executable module creates an exact OCCT box, exports STEP entirely in
memory, commits and canonically persists the one-body document, resolves the
same bytes, imports them through the strong boundary, inspects measurement and
topology, and re-exports deterministic STEP:

```ts theme={"system"}
import {
  EvaluatedSolid,
  createEvaluator,
  createImportedBodyDocument,
  design,
  mm,
  parseImportedBodyDocument,
  stringifyImportedBodyDocument,
  vec3,
  type CadResult,
  type ImportedBodyResourceDigest,
} from "invariantcad";

function valueOrThrow<T>(result: CadResult<T>): T {
  if (!result.ok) {
    throw new Error(
      result.diagnostics.map((item) => item.message).join("\n"),
    );
  }
  return result.value;
}

async function sha256(
  bytes: Uint8Array,
): Promise<ImportedBodyResourceDigest> {
  const digest = await crypto.subtle.digest(
    "SHA-256",
    Uint8Array.from(bytes),
  );
  const hexadecimal = Array.from(new Uint8Array(digest), (byte) =>
    byte.toString(16).padStart(2, "0"),
  ).join("");
  return `sha256:${hexadecimal}`;
}

const source = design("import-source");
const box = source.box("box", {
  size: vec3(mm(2), mm(3), mm(4)),
});
source.output("box", box);

async function runImportedBodyRoundTrip() {
  const evaluator = await createEvaluator({ profile: "mechanical-exact" });
  try {
    const sourceResult = valueOrThrow(
      await evaluator.evaluate(source.build()),
    );
    let sourceStep: Uint8Array;
    try {
      const output = sourceResult.output("box");
      if (!(output instanceof EvaluatedSolid)) {
        throw new Error("Expected the source output to be a solid");
      }
      sourceStep = output.export("step", {});
    } finally {
      sourceResult.dispose();
    }

    const digest = await sha256(sourceStep);
    const document = valueOrThrow(
      createImportedBodyDocument("verified-step-box", {
        id: "importedBox",
        resource: {
          id: "boxStep",
          digest,
          byteLength: sourceStep.byteLength,
          mediaType: "model/step",
          locations: ["memory:box.step"],
        },
        format: "step",
        units: { mode: "from-file" },
      }),
    );
    const canonicalJson = stringifyImportedBodyDocument(document);
    const reparsed = valueOrThrow(
      parseImportedBodyDocument(canonicalJson),
    );

    let resolverCalls = 0;
    const imported = valueOrThrow(
      await evaluator.evaluateImportedBody(reparsed, {
        resolver: (request) => {
          resolverCalls += 1;
          if (
            request.id !== "boxStep" ||
            request.digest !== digest ||
            request.byteLength !== sourceStep.byteLength ||
            request.mediaType !== "model/step"
          ) {
            throw new Error("Unexpected imported-body resource request");
          }
          return sourceStep;
        },
      }),
    );
    try {
      const measurements = imported.measure();
      const topology = valueOrThrow(imported.topology());
      const firstExport = imported.export("step", {});
      const secondExport = imported.export("step", {});

      return {
        canonicalRoundTrip:
          stringifyImportedBodyDocument(reparsed) === canonicalJson,
        resolverCalls,
        exact: imported.exact,
        representation: imported.representation,
        volume: measurements.volume,
        surfaceArea: measurements.surfaceArea,
        faces: topology.faces.length,
        exportedStepBytes: firstExport.byteLength,
        deterministicExport:
          firstExport.byteLength === secondExport.byteLength &&
          firstExport.every((byte, index) => byte === secondExport[index]),
      };
    } finally {
      imported.dispose();
    }
  } finally {
    evaluator.dispose();
  }
}

export const importedBodySummary = await runImportedBodyRoundTrip();
console.log(importedBodySummary);
```

The release gate compiles and executes
`examples/docs/imported-body-round-trip.ts`.

This slice does not provide imported-body healing or repair, multiple-body
selection, body sets, external components, assemblies, automatic location I/O,
media-type inference, a public general Document v7 alias, or integration with
the ordinary v6 design builder and `evaluate(...)`. Those remain separate
product milestones.

## Browser download

```ts theme={"system"}
const bytes = output.export("stl");
const blob = new Blob([bytes], { type: "model/stl" });
const url = URL.createObjectURL(blob);

try {
  const anchor = document.createElement("a");
  anchor.href = url;
  anchor.download = "part.stl";
  anchor.click();
} finally {
  URL.revokeObjectURL(url);
}
```

## Repository-only product-document staging

The ordinary v6 design builder still does not expose an imported-body or
body-set feature node. The narrow public workflow above is separate from the
repository-only broader product grammar. The repository contains
`stagedBodySetDesignV7(...)`, a source-only authoring facade for the exact graph
admitted by the staged evaluators. This is executable Document v7 evidence, not
an end-user product-document workflow: the package-root `DesignDocument`
alias, ordinary builder/evaluator, and migration target remain on the frozen v6
model, and no package subpath exposes the facade. The public one-body facade
does not make these broader types callable.

The staged facade authors:

* typed length, angle, mass-density, and scalar parameters, named parameter
  configurations, document-owned materials, typed part-material substitutions,
  and assembly-definition instance-suppression overrides;
* direct boxes, cylinders, and spheres by privately composing the existing v6
  builder;
* owner-bound solid DAGs whose leaves are those primitives or imported bodies
  and whose internal nodes are ordered `union(...)`, `subtract(...)`,
  `intersect(...)`, or transform operations, with typed `translate(...)`,
  `rotate(...)`, `scale(...)`, and `mirror(...)` conveniences;
* document-owned commitments with an explicit SHA-256 digest, byte length,
  media type, ordered location hints, and detached metadata;
* owner-bound imported-body leaves for STEP with file units or text/binary BREP
  with an explicit `mm`, `cm`, `m`, or `in` length unit;
* owner-bound body sets whose dense, non-empty ordered memberships reference
  facade-created primitive/import/Boolean/transform DAG roots;
* owner-bound parts whose geometry is one staged solid DAG root or one admitted
  body set;
* external-part handles that bind one named part output from a committed
  InvariantCAD document resource without publishing a local feature node;
* external-assembly handles that bind one named assembly output from a
  committed InvariantCAD document resource without publishing a local feature
  node; and
* acyclic nested fixed-placement product assemblies whose instances reference
  owned local parts, already-completed local assemblies, or either external
  handle and select inherited, base, or named child configuration contexts,
  plus outputs that directly target an imported body, body set, part, or staged
  product assembly.

Every imported node fixes healing to `none` and expects one solid. Its explicit
format chooses the reader; committed `mediaType` is provenance and resolver
context, not reader inference. The caller supplies the digest and byte-length
commitments; the facade does not read or hash the resource bytes. Ordered
resource locations are resolver hints only. Neither the facade nor the staged
evaluators perform file, URL, or package I/O. Authoring methods validate
namespaces, commitments, owner identity, material and configuration references,
dense collections, and unique member IDs. Build applies caller-selected
`DesignDocumentLimits` and strict v7 validation before returning detached,
deeply frozen v7 data. Immediate authoring ceilings default to
`10,000` resources, `100,000` aggregate location hints, and `16 MiB` of
aggregate UTF-8 location text. An individual body set is also rejected before
copying above the default `1,000,000` structural-value ceiling. Caller-selected
build limits can be stricter but cannot raise these immediate safeguards.
Parameter, configuration, material, part, assembly-instance, placement,
resource, import, unit-policy, and body-member options must be plain own-data
records, and required collections must be dense. Accessor-backed and unknown
fields are rejected without invocation or silent interpretation, and caller
metadata is detached.

The repository has four source-only staged geometry-evaluator slices:

* A direct imported-body output admits bytes only through the caller-supplied
  resolver, verifies the declared byte length and SHA-256 digest, and invokes
  the kernel's strong exact single-solid import contract.
* A direct body-set output preserves authored member order, stable member IDs,
  optional names, and detached metadata. Every listed member is active and no
  member is treated as a primary body. Its solid reference may point to a box,
  cylinder, sphere, imported-body leaf, or a bounded Boolean/transform DAG
  rooted in those leaves. Shared graph nodes are evaluated once without
  collapsing authored memberships.
* A direct part output preserves part metadata and effective material/density
  provenance while retaining an explicit single-solid or body-set geometry
  branch. Its geometry must be one supported solid DAG root or one body set
  admitted by the preceding slice. The staged facade authors exactly this part
  boundary through `material(...)`, `part(...)`, configuration
  `.partMaterial(...)`, and direct part `output(...)`.
* A product-assembly output iteratively expands active local assemblies,
  resolves direct external-part outputs, and expands one fixed external
  subassembly boundary into its child-local part leaves. It preserves full
  root-to-leaf occurrence paths, root-relative placements composed parent first,
  and each part occurrence's effective `inherit`, `base`, or named
  configuration context. Every containing assembly's context controls that
  definition's suppression and placement expressions, including explicit
  `false` unsuppression, before component admission. Active local and external
  leaves may use the same single-solid or multibody geometry admitted by the
  direct part slice, including verified imported leaves.

### Document-scoped external resources

The staged product evaluator resolves external document JSON from the root
document's resource registry before resolving geometry resources declared by
those children. Its resolver requests carry a frozen `documentScope`:

```ts theme={"system"}
type DocumentV7ResourceScope =
  | { readonly source: "root" }
  | {
      readonly source: "external";
      readonly resource: ResourceId;
      readonly digest: ResourceDigestIR;
    };
```

The root scope identifies commitments in the product document, including each
external document. An external scope identifies the admitted child registry by
the root resource ID and digest. Resolver implementations for this staged
operation must use both the scope and `request.id`: two child documents may
legitimately reuse the same document-local resource ID while resolving
different committed bytes. Ordinary `resolveResourcesV7(...)` requests remain
unscoped; `documentScope` belongs to this repository-only staged session, not a
new public 0.1.1 resolver contract.

Resolution is deterministic and two-phase. All selected external document
commitments are preflighted and resolved before child assembly expansion or
part preparation. Prepared child batches and kernel capabilities are then
preflighted before any child geometry resource callback, and all child geometry
bytes are admitted before document-body import callbacks run. Repeated
`(documentScope, resourceId)` commitments reuse verified retained bytes; the
same resource ID in a different scope remains distinct.

Native primitive/Boolean/transform body sets can run on either exact or
approximate kernels, and the result records the kernel representation as
`mesh`, `brep`, or `sdf` together with its exactness claim. Stock OCCT
constructs exact B-Rep geometry with partial Boolean history; a matched owned
facade supplies complete bounded evolution for the current Boolean only when it
proves the existing feature-scoped protocol. That promise cannot upgrade
partial history already carried by an operand, and the result's `exact` flag
describes geometry rather than complete history. Manifold constructs
approximate mesh geometry with no topology snapshots. Evaluation never falls
back from one backend to the other. An imported member, including an imported
leaf below Booleans or transforms, is different: the complete body set must use
an exact `brep` kernel with strong single-solid document-body import support.
Imported bytes cross the same verified-resource boundary as a direct
imported-body output. There is no weak `importShape(...)` fallback and no
automatic conversion to a mesh representation.

Executable stock-OCCT evidence resolves a commitment-verified STEP box,
subtracts a native tool, transforms the result, inspects partial topology,
exports STEP, and restores the native ownership baseline. Separate real
Manifold evidence evaluates configuration-sensitive native Boolean graphs
through nested products, BOM, mass, suppression, limits, and complete cleanup.
External-product OCCT evidence separately resolves a child document and its
scoped STEP resource, evaluates an imported/translated/Boolean child part beside
a native part through a nested local subassembly, reuses both exact child leaves
across two fixed-subassembly occurrences, exports retained child solids as STEP,
produces aggregate mesh/STL, and restores the native ownership baseline.

The staged body-set result owns its distinct kernel shapes until disposal.
Each member can produce a detached mesh and measurements. Topology and native
single-body STEP/BREP export remain gated by the kernel's separate
capabilities. A shared leaf can be evaluated once without collapsing its
distinct authored memberships; shared Boolean and transform nodes are memoized
the same way. Aggregate tessellation preserves the authored member sequence,
while aggregate STL and OBJ export are mesh-derived and therefore explicitly
approximate/lossy even when the source bodies are exact. No exact aggregate
STEP or BREP export is available: the evaluator does not fuse the bodies,
invent a compound, or otherwise reinterpret the authored set. The selected
kernel must advertise and implement `boolean` before resolver or shape work,
and malformed optional exact-evolution metadata fails closed. A null or exactly
zero-volume subtraction/intersection returns error-level `EMPTY_RESULT`; an
impossible empty union or invalid measurement is a kernel protocol failure.
There is no staged `allowEmpty` option. Failure releases every distinct
acquired or intermediate shape exactly once. Success keeps those shapes live
until the staged design is disposed; subsequent facade and per-body solid
operations then fail deterministically. The supplied kernel is borrowed and is
never disposed by this operation.

The staged operation bounds selected outputs, caller parameter overrides,
authored memberships, distinct primitive/import leaves, all solid-graph nodes,
all Boolean target/tool and transform input edges, authored transform
operations, documents, and resolved resources. Repeated Boolean tool
references count as repeated edges. The solid-DAG ceilings are
`maxSolidGraphNodes`, `maxSolidDependencyLinks`, and
`maxTransformOperations`, each defaulting to `100,000`; `maxDistinctSolids`
separately counts leaves. Those admission limits do not bound mesh buffers
created by later facade calls; applications handling hostile or very large
tessellations still need a disposable worker or process and an
application-owned output ceiling.

For a direct part, a named configuration can replace the authored `materialId`.
An explicit part density still overrides the effective material density, and a
legacy material label or material name is never used as a catalogue lookup.
Length and density parameters first resolve in the selected configuration and
may then be specialized by bounded caller overrides. The one-row part BOM and
`physicalMassProperties()` use one uniform effective density across all
memberships. Mass is additive over independent bodies: repeated aliases and
spatial overlaps each contribute once per authored membership rather than
being fused or unioned. The numeric result inherits the selected backend's
measurement quality; a kernel capability marked exact is not a separate proof
of mathematically exact floating-point mass.

Part-level `mesh()` and STL/OBJ export are aggregate tessellation views and are
therefore approximate/lossy. Exact native export remains a per-solid or
per-body capability. Multibody parts do not expose aggregate geometric
measurement, exact aggregate STEP/BREP, a cross-body topology namespace,
interference subtraction, or primary-body inference. Bare body sets still have
no aggregate mass contract; the part supplies the uniform-density semantics.

For a product assembly, repeated part instances retain distinct full occurrence
paths and BOM quantities. One local part result is reused for equal
`(part, effective configuration)` contexts; one direct external-part result is
reused for equal `(resource, output, effective child configuration)` contexts.
Fixed-subassembly leaves reuse geometry by
`(resource, child part node, effective child configuration)`. Distinct external
output aliases retain distinct component, diagnostic, and BOM identity even
when they select the same child part or assembly and share the same evaluated
geometry. Neither optimization is a cross-run cache or geometric-equivalence
claim.

Aggregate product mesh, binary/ASCII STL, and OBJ apply each root-relative
occurrence placement and remain approximate/lossy. Exact native export remains
available from a retained child solid when its kernel supports the requested
format: the stock-OCCT product evidence exports the child as STEP. The product
itself rejects STEP/BREP aggregate export with `EXPORT_UNSUPPORTED`; evaluation
does not fuse child solids or invent a compound. The contextual BOM keeps
unlike component/configuration states separate, while physical mass applies
each effective density and placement before combining mass, center of mass, and
inertia.

A suppressed assembly edge prunes its entire subtree before descendant
admission or work accounting. Traversal is bounded by `maxAssemblyDepth`,
`maxOccurrencePathSegments`, scanned-instance, active-occurrence, placement,
and downstream part/resource ceilings. Solid-graph nodes, all Boolean
target/tool and transform input edges, and transform operations are counted
globally by `(node, effective configuration)` across active occurrences:
repeated occurrences in one context share the charge, while different contexts
are independent. Repeated Boolean references still charge every authored edge.
An active external part or fixed subassembly is evaluated only after its
committed child document has been admitted. Child `inherit` maps parent base to
child base or a parent named configuration to the same child ID; explicit
`base` and `named` selectors target the child directly. Descendant selectors,
suppression, and placement expressions are interpreted inside that child
document. Root caller parameter overrides never flow into it.

An external-part handle must select a direct part output, and an
external-assembly handle must select a direct assembly output. The latter may
expand child-local parts and nested local assemblies. Each active occurrence
path may cross only that one external-document boundary: a suppressed nested
external component is inert, while an active one is rejected before nested
resolution or child geometry/kernel work. The facade cannot construct a local
cycle because it accepts only already-completed same-builder local assembly
handles; strict document admission and evaluation reject hand-authored
recursive local graphs.

The authoring facade, all four staged geometry-evaluator slices, and the
kernel-independent datum resolver remain repository-only source work for 0.2:
none is exported by the public 0.1.1 package root, available from a package
subpath, or integrated with the public builder or CLI. The facade can author
datum points, axes, planes, and coordinate systems, but they are resolved by
selected node ID rather than published as design outputs or consumed by
sketches or shape algebra.

The facade authors direct external-part and external-assembly handles, but not a
recursive external product graph. External part outputs and the local part
leaves reached through one selected external assembly must still be admitted by
the existing staged part evaluator; the product evaluator does not widen the
child's supported feature families. A migrated v6 part backed by an extrusion,
for example, is rejected before geometry or scoped child-resource work. Cyclic
local-assembly graphs, Boolean or transform inputs that are body sets, parts, or
assemblies, other body-consuming operations, per-body materials, and general
solid graphs beyond primitive/import/Boolean/transform DAGs remain unsupported.
The facade cannot publish a direct primitive or a generic Boolean or transformed
solid output either; generic solid geometry must be retained by a body set or
part. The narrower imported-body handle remains the only directly publishable
solid-like staged reference.

The operations perform no location I/O and admit no healing beyond `none`. A
resource's `mediaType` is committed provenance passed to the resolver; it is
not used to choose the reader or accepted as a substitute for the imported-body
node's explicit `format`. Assembly mates, motion, interference/collision,
assembly-wide topology or geometric measurement, and exact aggregate STEP/BREP
remain unsupported. The narrow public one-body facade applies the closed
protocol-v1 format/media/unit table documented above; that policy does not
promote this broader product grammar.

There are deliberately two kernel boundaries:

* `nativeImports` plus `importShape(...)` is weak exchange support. It may
  return any shape accepted by the backend.
* `documentBodyImport` plus `importDocumentBody(...)` is the versioned strong
  boundary required by a canonical imported-body node.

Stock OCCT admits STEP only with `{ mode: "from-file" }`. Text and binary BREP
are unitless, so they require `{ mode: "declared", length: "mm" | "cm" | "m" |
"in" }`. Protocol v1 requires `{ healing: { mode: "none" } }`.

```ts theme={"system"}
import {
  inspectKernelDocumentBodyImportCapabilities,
  kernelSupportsDocumentBodyImport,
} from "invariantcad";
import { createOcctKernel } from "invariantcad/kernels/occt";

const kernel = await createOcctKernel();
try {
  const inspection = inspectKernelDocumentBodyImportCapabilities(
    kernel.capabilities,
  );
  if (
    inspection.status !== "valid" ||
    !kernelSupportsDocumentBodyImport(
      kernel.capabilities,
      "brep-binary",
      "declared",
    ) ||
    kernel.importDocumentBody === undefined
  ) {
    throw new Error("The selected kernel cannot import this document body");
  }

  const shape = kernel.importDocumentBody(brepBytes, {
    format: "brep-binary",
    units: { mode: "declared", length: "mm" },
    healing: { mode: "none" },
  });
  try {
    console.log(kernel.measure(shape).volume);
  } finally {
    kernel.disposeShape(shape);
  }
} finally {
  kernel.dispose();
}
```

This low-level call snapshots the supplied bytes but does not verify a document
resource digest. Every staged evaluator that admits an imported leaf composes
the existing resolver and strong importer: byte-length and SHA-256 admission
completes before the imported parser is called. Missing resolvers, failed
resolution, integrity mismatches, limits, cancellation, unsupported capability
combinations, and kernel failures remain structured diagnostics. The strong
importer requires exactly one valid, positive-volume solid with no loose
topology and reports only partial imported history. It does not invent stable
feature lineage or authored topology roles.

Native STEP/BREP parsers can allocate or execute beyond JavaScript byte limits.
Applications handling hostile files still need a disposable worker or process
boundary; cooperative cancellation cannot preempt a synchronous native parser.

## Exchange is not artifact caching

STL, OBJ, STEP, and BREP are interoperability formats. They do not preserve the
complete evaluator wrapper state, topology evolution history, analytic
overrides, or compatibility fingerprint needed for transparent feature-cache
reuse. See [design impact and hashes](/analysis/design-impact-and-hashes).
