# T2DPLM Open Connector Format (OCF) v1.0

**Document type:** Format Specification
**Status:** Draft Standard
**Format version:** 1.0
**Document revision:** 2 (2026-09-16)
**Scope:** Vendor-neutral, CAD-tool-agnostic
**Companion documents:**
- *T2DPLM OCF v1.0 — Implementation Guide* (how to build a producer for a specific tool; required reading before writing a connector)
- *T2DPLM OCF v1.0 Validator* (reference implementation of the structural checks in this document)

> **Revision note.** Revision 2 does not change the wire format. Every file that was conformant under Revision 1 is still conformant. Revision 2 writes down rules that were previously implicit — several of which the reference validator already enforces — and removes assumptions that only held for file-per-component CAD tools. See Appendix A for the full change list.

---

## Abstract

The T2DPLM Open Connector Format (OCF) is a vendor-neutral JSON exchange format for describing the component tree of a CAD assembly or design at the moment it is saved. A **producer** — any piece of software that watches a CAD or design tool and writes OCF files — emits one OCF file per save. A **consumer** (for example, the T2DPLM ingestion pipeline) reads that file and compares it against prior versions to detect real design changes.

This document defines the format only: the file layout, the required fields, the two hard correctness rules, the behavioral requirements a producer must satisfy, and the tests a producer must pass to be considered conformant. It does not describe how to build a producer for any particular CAD tool. It makes no reference to any CAD vendor's SDK, API, or product-specific concepts, and contains no source code.

---

## Table of Contents

1. Scope
2. Conformance Language
3. Terminology
4. Output File Requirements
5. File Structure and Field Definitions
6. Rule A — Stable Identity
7. Rule B — No Noisy Values
8. Producer Behavior Requirements
9. Configuration Requirements
10. Conformance Test Suite
11. Relationship to Other Documents
- Appendix A — Changes in Revision 2
- Appendix B — Conformance checklist

---

## 1. Scope

This specification defines the OCF v1.0 file format and the rules a conforming producer must follow when generating it. It applies to any software, for any CAD or design tool, that emits OCF files for consumption by T2DPLM or another OCF-aware system.

This specification is intentionally CAD-tool-agnostic. It defines a data contract, not an implementation. Guidance specific to any individual CAD tool's API or SDK — including how to obtain a persistent component reference, how to hook a save event, or how to package and install a plugin — is out of scope for this document and belongs in the Implementation Guide.

**1.1 Tool-model neutrality.** OCF makes no assumption about how the source tool stores a design. In particular, it is equally applicable to:

- **file-per-component tools**, where each part and sub-assembly is its own file on disk referenced by a parent assembly file; and
- **single-document tools**, where the entire design — every part, sub-assembly and feature — lives inside one file on disk;
- **cloud or database-backed tools**, where components have no on-disk file at all.

A producer for any of these MUST emit the same field set, in the same shape, with the same rules. Where a concept in Section 5 has no direct equivalent in the source tool, Section 5.7 states what to emit instead. A producer MUST NOT invent a field, omit a field, or change a field's type to suit its source tool.

**1.2 Out of scope.** Quantity rollup, BOM flattening, revision numbering, change classification, approval workflow and any other interpretation of the data are consumer responsibilities. A producer reports the tree as saved; it does not interpret it.

## 2. Conformance Language

The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL** in this document are to be interpreted as normative conformance levels, in the conventional sense used by technical standards (compare RFC 2119):

- **REQUIRED / MUST**: an absolute requirement. A file or producer that fails to satisfy this is not OCF v1.0 conformant.
- **NOT ALLOWED / MUST NOT**: an absolute prohibition.
- **SHOULD / RECOMMENDED**: strongly advised, but a conformant implementation may deviate for documented reasons.
- **MAY / OPTIONAL**: genuinely discretionary.

**Note on this version:** In OCF v1.0, every field defined in Section 5 is REQUIRED — there are no OPTIONAL fields in the schema. Several REQUIRED fields permit an empty string, an empty object, or `null` as a valid value (see the field tables in Section 5). Permitting an empty value is not the same as making the field OPTIONAL: omitting a REQUIRED field entirely is NOT ALLOWED.

## 3. Terminology

- **Producer**: any software component that generates OCF-conformant files from a CAD design. (Called a "connector" in casual usage.)
- **Consumer**: any software that reads and processes OCF files, such as the T2DPLM ingestion pipeline.
- **Source tool**: the CAD or design application the producer observes. Referred to generically throughout; this document never assumes a specific one.
- **Assembly / design**: the CAD file or document being saved, and the tree of components it contains.
- **Component instance**: one occurrence of a part or sub-assembly within the design's tree. If the same underlying part appears more than once, each occurrence is a distinct component instance.
- **Root component**: a component instance whose `parentId` is `null`.
- **Component forest**: the structure formed by the `components` array. One or more root components, each with zero or more descendants (see 5.4.3).
- **User-defined property**: a property whose value a designer sets or edits as part of doing design work.
- **Tool-internal property**: a property maintained by the source tool for its own bookkeeping — engine state, attachment modes, link flags, element-map or schema version stamps, cache markers, dirty/touched flags (see 7.5).
- **Watched folder**: the configured filesystem location where a producer writes its output files, and which a consumer monitors for new or updated files.

## 4. Output File Requirements

**4.1 Cardinality.** A producer MUST write one output file per save of a design. Saving the same design again MUST result in either the same file being overwritten, or a new file being written under a filename derived from the same `meta.assemblyId` — either is acceptable, provided `meta.assemblyId` stays the same across saves of the same design.

**4.2 Filename.** The output filename MUST be `asm_<assemblyId>.json`, where `<assemblyId>` is the value of `meta.assemblyId`.

**4.2.1 Filename-safe assembly id.** Because `meta.assemblyId` becomes part of a filename, it MUST contain only characters that are safe in a filename on every platform the producer supports. Producers MUST restrict `assemblyId` to ASCII letters, digits, hyphen (`-`), underscore (`_`) and period (`.`). Path separators, whitespace, colons and other reserved characters are NOT ALLOWED. A tool-supplied identifier that does not satisfy this MUST be hashed or encoded into one that does, deterministically (see 6.2).

**4.2.2 Renaming in transit.** Conformance is judged on the name the producer writes. A consumer, transport layer or upload mechanism MAY rename or prefix the file afterwards; that renaming does not make the producer non-conformant, and the reference validator provides a switch to skip the filename check when validating content that has already been renamed.

**4.3 Location.** The output file MUST be written to the configured watched folder (Section 9).

**4.4 Encoding.** The output file MUST be UTF-8 encoded with **no byte-order mark (BOM)**. This is a hard requirement: a BOM breaks the downstream reader. A UTF-8 BOM, a UTF-16 or UTF-32 BOM, or any byte sequence that is not valid UTF-8, all make the file non-conformant.

**4.5 Atomicity.** A producer MUST write the output file atomically where the host platform allows it (for example: write to a temporary filename, then rename into place), so that a file-watching consumer never reads a partially written file.

**4.6 Nothing else in the watched folder.** A producer MUST NOT write logs, lock files, temporary artifacts that outlive the write, or any other non-OCF file into the watched folder. Producer logs go next to the producer (Section 8.1), not next to its output.

## 5. File Structure and Field Definitions

**5.1 Top level.** An OCF file has exactly two top-level keys: `meta` and `components`. No other top-level keys are permitted. The root of the file MUST be a JSON object; `meta` MUST be a JSON object; `components` MUST be a JSON array.

**5.2 Schema (informative JSON example).**

```json
{
  "meta": {
    "assemblyId": "string",
    "assemblyName": "string",
    "savedAt": "ISO-8601 timestamp",
    "sourcePath": "string",
    "cadTool": "string",
    "toolVersion": "string"
  },
  "components": [
    {
      "id": "string",
      "partNumber": "string",
      "configuration": "string",
      "parentId": "string or null",
      "fileName": "string",
      "transform": {
        "position": { "x": 0.0, "y": 0.0, "z": 0.0 },
        "rotation": { "x": 0.0, "y": 0.0, "z": 0.0 }
      },
      "properties": { "key": "value" },
      "suppressed": false,
      "virtual": false
    }
  ]
}
```

**5.3 `meta` fields.** These fields are informational and are **not** compared for change detection, with the single exception noted for `savedAt`. Every `meta` value MUST be a JSON string — including `toolVersion`, which is a version *string*, not a number.

| Field | Type | Conformance | Definition |
|---|---|---|---|
| `assemblyId` | string | REQUIRED | Stable identifier for the whole assembly/design. Drives the output filename, so it MUST satisfy 4.2.1. MUST NOT change across ordinary saves of the same design, including when the design file is moved or renamed on disk. MUST NOT be empty. |
| `assemblyName` | string | REQUIRED | Human-readable name of the assembly/design as shown by the source tool. |
| `savedAt` | string (ISO-8601) | REQUIRED | Timestamp of this save, formatted `YYYY-MM-DDThh:mm:ss`, optionally followed by fractional seconds, optionally followed by `Z` or `±hh:mm`. UTC (`Z`) is RECOMMENDED. This is the **only** field in the entire file permitted to differ between two saves of an otherwise-unchanged design. |
| `sourcePath` | string | REQUIRED | The original file path of the design on disk at save time. Informational only — MUST NOT be used as, or as part of, any component's identity. If the source tool has no on-disk path (cloud or database-backed designs), emit the tool's canonical document locator, or an empty string if it has none. |
| `cadTool` | string | REQUIRED | Identifies the source tool that produced the file. The value is opaque to this specification. Producers SHOULD use a stable, unabbreviated tool name and keep it constant across releases. |
| `toolVersion` | string | REQUIRED | Version string of **the producer itself**, for debugging — not the version of the source tool. |

**5.4 `components` fields.** This is an array with one entry per component instance in the tree (Section 8.3). Every entry MUST be a JSON object. Entries in this array **are** compared for change detection, which is why Rule B (Section 7) applies to every field here.

| Field | Type | Conformance | Definition |
|---|---|---|---|
| `id` | string | REQUIRED | Stable identity, per Rule A (Section 6). MUST be non-empty and MUST be unique within the file (6.5). |
| `partNumber` | string | REQUIRED | The part number or equivalent designation as tracked by the source tool, resolved per 5.7.2. Empty string is permitted if the source tool has no such concept for a given component. |
| `configuration` | string | REQUIRED | Active configuration/variant name, if the source tool supports configurations. Empty string is permitted if not applicable. |
| `parentId` | string or `null` | REQUIRED | The `id` of the parent component/sub-assembly, or `null` for a root component. Encodes the assembly hierarchy. A non-null `parentId` MUST refer to another component's `id` present in the same file. An empty string is NOT ALLOWED — use `null`. |
| `fileName` | string | REQUIRED | The component's underlying file name, resolved per 5.7.1. MUST NOT be used for identity. |
| `transform.position` | object of exactly 3 JSON numbers (`x`, `y`, `z`) | REQUIRED | Position in the source tool's native units (5.7.5). Numeric strings are NOT ALLOWED. |
| `transform.rotation` | object of exactly 3 JSON numbers (`x`, `y`, `z`) | REQUIRED | Rotation in the source tool's native units and convention (5.7.5). Numeric strings are NOT ALLOWED. |
| `properties` | flat object of key/value pairs | REQUIRED | The component's user-defined properties, selected per 5.7.3 and filtered per 7.5. Empty object is permitted if none exist. Values MUST be flat scalars — nested objects or arrays inside `properties` are NOT ALLOWED. |
| `suppressed` | boolean | REQUIRED | Whether the source tool marks this component suppressed/inactive. MUST be a JSON boolean: the strings `"true"`/`"false"` and the numbers `0`/`1` are NOT ALLOWED. |
| `virtual` | boolean | REQUIRED | Whether the component is a virtual/in-context/non-file-backed component, if the source tool has such a concept. `false` if not applicable. Same type rule as `suppressed`. |

**5.4.1 `transform` shape.** `transform` MUST be a JSON object containing exactly the keys `position` and `rotation`. Each of those MUST be a JSON object containing exactly the keys `x`, `y` and `z`, each a JSON number. No other key is permitted at any of these three levels.

**5.4.2 `properties` value types.** A property value MUST be a JSON scalar: string, number, boolean or `null`. A producer SHOULD choose one serialization strategy for a given source tool and keep it constant — for example, emitting every value as a string, or emitting native types — because switching strategy between releases makes every component look changed (Rule B).

**5.4.3 Hierarchy is a forest, not a single tree.** A file MAY contain more than one root component. Some tools have exactly one root; others expose several top-level items in one document, and both are conformant. Regardless of root count, the `parentId` graph MUST be acyclic: a component MUST NOT be its own parent, and no chain of `parentId` references may return to its starting component. A cycle can never describe a real assembly and makes the file non-conformant.

**5.5 Component inclusion.** Suppressed and virtual components MUST be included in `components`, flagged via the `suppressed`/`virtual` booleans — they MUST NOT be omitted. A component's entry MUST disappear from the file only when that component has genuinely been deleted from the design, never merely because it is suppressed, virtual, hidden, filtered out of the tool's own tree view, or excluded by a display setting.

**5.6 Extensibility.** A conformant OCF v1.0 file MUST NOT contain fields beyond those defined in this section, and MUST NOT omit any REQUIRED field. There is no vendor-extension or custom-field mechanism defined in v1.0. Tool-specific information that has no home in the schema belongs in the producer's own documentation (Section 11 of the Implementation Guide), not in the file.

**5.7 Resolving schema fields for tools that lack the underlying concept**

This subsection is what makes one schema work across every source tool. In each case the producer MUST pick the highest available option and MUST disclose which one it used, in its own documentation.

**5.7.1 `fileName` when components are not separate files.** In a single-document tool, every component shares one on-disk file; in a cloud tool there may be no file at all. Resolution order:

1. the component's own underlying file name, if the tool stores components as separate files;
2. otherwise, the file name of the document that contains the component (so every component in a single-document design carries the same value — this is expected and conformant);
3. otherwise, an empty string.

`fileName` is informational in all three cases and MUST NOT participate in identity (6.2).

**5.7.2 `partNumber` when the tool has no part-number concept.** Resolution order:

1. the value of the property configured as the part-number source (Section 9.1);
2. otherwise, the tool's native part-number or designation field, if it has one;
3. otherwise, the component's stable label or name as the tool shows it in its tree;
4. otherwise, an empty string.

The value MUST be emitted verbatim, exactly as the tool reports it. A producer MUST NOT trim whitespace, change case, strip suffixes or otherwise normalize it: two distinct components can differ only by such characters, and normalizing them makes distinct parts look identical to the consumer. Cleanup, if wanted, is a consumer-side decision.

**5.7.3 `properties` selection.** `properties` carries *user-defined* properties. A producer MUST exclude tool-internal properties as defined in 7.5, and MUST make the inclusion rule configurable rather than hard-coded (Section 9.1), because which keys are user-defined differs by tool and by customer convention.

**5.7.4 `configuration` when the tool has no variants.** Emit an empty string. Do not substitute a revision, a display state, a view or a layer name.

**5.7.5 Units and rotation convention.** OCF v1.0 carries no units field and no rotation-convention field, and none may be added (5.6). Therefore a producer MUST document, outside the file, the length unit and the rotation representation and order it emits, and MUST keep both constant for the lifetime of a `meta.assemblyId`. Changing units or rotation convention between releases will present as every component having moved.

## 6. Rule A — Stable Identity

This is one of two hard rules in this specification. Violating it causes the downstream consumer to misreport changes.

**6.1** Each component's `id` MUST remain identical across saves for as long as that component instance has not changed.

**6.2** A producer MUST derive `id` from whatever the source system exposes as a true persistent/stable reference for a component instance (for example, a persistent id, a stable GUID, or an occurrence path that survives a save), and MUST hash that reference into a fixed-length string. SHA-256 is RECOMMENDED as the hash algorithm. The hashed input MUST NOT include anything from 7.1 — no timestamp, no absolute path, no session or machine identifier — and MUST NOT include `sourcePath`, since moving the design on disk is not a design change.

**6.3 Fallback when no persistent reference exists.** If the source system provides no true persistent/stable reference for a component instance, the producer:

- MUST disclose this limitation explicitly in its accompanying documentation;
- MUST use the most stable available substitute instead (typically a combination of the component's file name and its position in the assembly tree); and
- MUST clearly document that identity may break under this fallback if a component is renamed or reordered.

A producer MUST NOT silently use an unstable substitute (such as a raw index that can shift between saves) without disclosing that it has done so.

**6.4** Conformance to Rule A is verified by the stable-ID test (Section 10, Test 1) and the move/delete tests (Section 10, Tests 6–7).

**6.5 Uniqueness.** Every `id` MUST be unique within a file. Two entries sharing an `id` mean the producer cannot distinguish two component instances, which is a Rule A failure whatever the cause: an identity scheme that ignores occurrence, a hash collision, or a duplicated traversal. This is checkable in a single file and is enforced by the reference validator.

**6.6 Opacity.** `id` is opaque to the consumer. A consumer MUST NOT parse, split or infer meaning from it, and a producer MUST NOT rely on any consumer doing so.

## 7. Rule B — No Noisy Values

This is the second of the two hard rules.

**7.1** Any value that changes on its own between saves without reflecting a real design change — timestamps, temporary or session-specific file paths, machine-specific paths, cache locations, or similar — MUST live only in `meta`, and MUST NOT appear anywhere inside `components`.

**7.2** `components` MUST contain only values that change when, and only when, the actual design changes.

**7.3 Rationale.** The downstream consumer detects change by comparing each component entry for exact equality across saves. A single noisy value inside a component entry makes every save look like a change, even when nothing in the design moved.

**7.4** Conformance to Rule B is verified by the noise test (Section 10, Test 4).

**7.5 Tool-internal properties are noise.** The most common Rule B failure in practice is copying every property the tool exposes into `properties`. A producer MUST NOT emit, inside `components`, any property that is maintained by the tool rather than by the designer, including:

- schema, element-map or internal-format version stamps — these change when the user upgrades the CAD tool, with no design change at all;
- dirty, touched, recompute or cache-state flags;
- link, attachment and reference bookkeeping that the tool rewrites on load or recompute;
- session, document or view state;
- anything containing an absolute path, a temporary path or a machine name.

If it is unclear whether a given key is user-defined, the safe default is to exclude it and let the customer add it via configuration (Section 9.1). Excluding a property loses information; including a noisy one breaks change detection for the whole component.

**7.6 Deterministic serialization.** Test 1 requires two saves of an unchanged design to differ only in `meta.savedAt`, which means serialization itself MUST be deterministic:

- the order of entries in `components` MUST be stable across saves of an unchanged design (traversal order is fine, as long as it is reproducible);
- the order of keys within each object MUST be stable;
- number formatting MUST be stable and locale-independent — the same value MUST serialize to the same text every time (in particular, a decimal separator MUST NOT follow the machine's locale, and precision MUST NOT vary between runs);
- the order of keys within `properties` MUST be stable; sorting them is RECOMMENDED.

A consumer MUST NOT rely on component ordering to convey meaning; hierarchy is carried by `parentId` alone (5.4.3).

## 8. Producer Behavior Requirements

**8.1 Fault isolation.** A producer MUST NOT crash the host application. Every operation MUST be wrapped so that any error is written to a local log file next to the producer, and the underlying save operation completes normally regardless of producer failure. A producer MUST NOT block, delay perceptibly, or alter the result of the user's save.

**8.2 Tree traversal.** A producer MUST walk the full component tree at every level, not only the top level. Depth limits, node-count caps and early exits are NOT ALLOWED: a truncated file is indistinguishable, to the consumer, from a design in which the missing components were deleted.

**8.3 Occurrence semantics.** A producer MUST emit one `components` entry per component **instance**. If the same underlying part appears more than once in the assembly, the producer MUST emit one entry per occurrence. (Counting or quantity rollup across occurrences is a downstream consumer responsibility, not the producer's.)

**8.4 Atomic write.** See Section 4.5.

**8.5 No side effects on the design.** A producer MUST treat the design as read-only. It MUST NOT modify, add or remove properties, mark the document dirty, trigger a recompute that alters stored state, or cause the tool to prompt the user.

**8.6 No network access.** A producer MUST NOT make network calls, emit telemetry, or transmit design data anywhere. Its only output is the OCF file in the watched folder and its own local log.

**8.7 Partial-failure behavior.** If the producer cannot read one component's data, it MUST NOT silently drop that component from `components` — dropping it reads downstream as a deletion. It MUST either emit the component with the fields it could read and the specified empty values for the rest, and log the failure; or abandon the file entirely and log that, leaving the previous file in place. Which of the two it does MUST be documented.

## 9. Configuration Requirements

**9.1** A producer MUST read, at minimum, the following from an external, plain configuration source (not from source code):

- the watched folder path where output files are written;
- the name of the property (if applicable) used as the source for `partNumber` (5.7.2); and
- the rule determining which properties are emitted in `properties` — an allow-list, a deny-list, or both (5.7.3, 7.5).

**9.2** A producer MUST NOT hard-code the watched folder path or the property name.

**9.3** A producer MUST apply documented defaults and keep running if the configuration source is missing or partly invalid, logging what it fell back to. It MUST NOT crash the host application over a configuration problem (8.1).

## 10. Conformance Test Suite

An OCF v1.0 producer is conformant only when all of the following pass. Step-by-step procedures for running each test by hand are in the Implementation Guide, Section 11.

1. **Stable-ID test.** Save the same design twice with no edits. The two output files MUST be identical except for `meta.savedAt`.
2. **Completeness test.** Position, rotation, all user-defined properties, hierarchy (`parentId`), and suppressed/virtual flags MUST all be present and correct for every component.
3. **Encoding test.** The output file MUST be UTF-8 with no BOM.
4. **Noise test.** No timestamp, temporary or session-specific path, or tool-internal property (7.5) MUST appear anywhere inside `components`. Saving an unchanged design after restarting the CAD tool, and after upgrading it, MUST still produce a file that differs only in `meta.savedAt`.
5. **Fault-isolation test.** Force an error during export (for example, make the output folder temporarily unwritable). The error MUST be logged, and the host CAD tool's save MUST still complete normally.
6. **Move test.** Move one component and save. Only that component's `transform` MUST change; every other component's `id` and values MUST stay identical.
7. **Delete test.** Delete one component and save. That component's entry MUST disappear from `components`; no other entry MUST change.
8. **Structural-validation test.** Every output file MUST pass the reference OCF v1.0 validator with exit code `0`, including for a design that exercises nesting, repeated occurrences, suppressed components, virtual components and empty-valued fields.

**10.1 What a single file can and cannot prove.** Tests 3 and 8 are properties of one file and are machine-checkable. Tests 1, 4, 6 and 7 are statements about behavior across saves and can only be verified by diffing two or more real saves. Test 2 requires comparing the file against the design as the tool shows it. Passing the validator is necessary for conformance, not sufficient.

## 11. Relationship to Other Documents

This document is the complete format contract: the JSON layout, field definitions, the two hard rules, producer behavior requirements, configuration requirements, and the conformance test suite. It contains no vendor-specific guidance and no source code.

Anyone building a producer for a specific CAD tool — including how to obtain a persistent component reference from that tool's API, how to hook its save event, how to scope and package the plugin, delivery and licensing considerations, and vendor API terms-of-use considerations — should consult the companion *T2DPLM OCF v1.0 — Implementation Guide*.

The reference validator checks a single file against Sections 4.2, 4.4, 5 and 6.5 of this document. This specification is the single source of truth: where the validator and this document disagree, this document is correct and the validator has a bug.

---

## Appendix A — Changes in Revision 2

No change to the wire format. Revision 1 files remain conformant.

**Made explicit (already enforced by the reference validator):**
- `id` must be non-empty and unique within the file (6.5).
- `parentId` must not be an empty string, must not self-reference, and must not form a cycle (5.4, 5.4.3).
- `transform` contains exactly `position` and `rotation`; each contains exactly numeric `x`, `y`, `z` (5.4.1).
- `suppressed` and `virtual` must be JSON booleans, not strings or numbers (5.4).
- All `meta` values are strings; `savedAt` follows a stated ISO-8601 profile (5.3).
- The file root is a JSON object and `components` is a JSON array (5.1).
- UTF-16/UTF-32 BOMs and invalid UTF-8 are also non-conformant, not only the UTF-8 BOM (4.4).

**Generalized away from file-per-component tools:**
- Tool-model neutrality stated up front (1.1).
- `fileName` resolution for single-document and cloud tools; identical values across a design are conformant (5.7.1).
- `partNumber` resolution order, with verbatim emission and no normalization (5.7.2).
- `configuration` for tools without variants (5.7.4).
- `sourcePath` for designs with no on-disk path (5.3).
- Multiple root components are explicitly allowed (5.4.3).
- Units and rotation convention must be documented externally and held constant (5.7.5).

**New normative requirements:**
- `assemblyId` must be filename-safe (4.2.1); renaming in transit does not affect conformance (4.2.2).
- Nothing but OCF files in the watched folder (4.6).
- Tool-internal properties are noise and must be excluded (7.5) — the most common Rule B failure observed in practice.
- Deterministic serialization: stable ordering, stable key order, locale-independent number formatting (7.6).
- Identity input must exclude paths and session data (6.2); `id` is opaque (6.6).
- Read-only access to the design (8.5); no network access (8.6); defined partial-failure behavior (8.7).
- Property inclusion rule must be configurable (9.1); producer must survive bad configuration (9.3).
- Test 8: every output must pass the reference validator; single-file checks are necessary but not sufficient (10, 10.1).

## Appendix B — Conformance checklist

Structural, checkable per file (reference validator):

- [ ] UTF-8, no BOM; syntactically valid JSON; root is an object
- [ ] Exactly `meta` and `components` at the top level
- [ ] All six `meta` fields present, strings, `savedAt` ISO-8601
- [ ] Filename is `asm_<assemblyId>.json`, `assemblyId` filename-safe
- [ ] All nine component fields present on every entry, correct types, no extras
- [ ] `id` non-empty and unique; `parentId` null or a resolvable id; no self-parent, no cycles
- [ ] `transform` exactly position/rotation, each exactly numeric x/y/z
- [ ] `properties` flat; `suppressed`/`virtual` real booleans

Behavioral, checkable only across saves (Section 10 tests):

- [ ] Two unchanged saves differ only in `meta.savedAt` — including across a tool restart and a tool upgrade
- [ ] No tool-internal or path-bearing property inside `components`
- [ ] Move changes one `transform` only; delete removes one entry only
- [ ] Suppressed and virtual components present, not omitted
- [ ] One entry per occurrence, full-depth traversal
- [ ] Export failure is logged and the host save still completes

Documented by the producer (not in the file):

- [ ] Identity source used, and the fallback disclosure if no persistent reference exists
- [ ] Units and rotation convention
- [ ] Property inclusion rule and part-number source
- [ ] Partial-failure behavior

---

*End of T2DPLM Open Connector Format (OCF) v1.0, Revision 2.*

---

## License and disclaimer

Copyright (c) 2026 Thought2Design Systems. This document is released under the **MIT License**; the full text is in the `LICENSE` file distributed with it and at <https://www.thought2design.com/ocf/LICENSE>.

- **No warranty.** This document is provided "AS IS", without warranty of any kind. Thought2Design Systems is not liable for any claim, damages or other liability arising from its use, or from any software built with its help.
- **Not legal advice.** Nothing here is legal advice. You are solely responsible for confirming that you legally own or are licensed to use your CAD tool, and that writing and running a producer against its API is permitted by that vendor's license and API terms of use.
- **No vendor code, no affiliation.** Thought2Design Systems supplies no CAD-vendor SDK, API binding or code that calls a vendor API, and does not receive or distribute producers you build. Names of CAD tools and vendors are trademarks of their respective owners; mentioning them implies no affiliation, endorsement or sponsorship.
- **Your producer is yours.** Thought2Design Systems claims no ownership of, and takes no responsibility for, a producer you create. Its licensing, and your compliance with the vendor's terms, are your responsibility.
