THE FORWARD TRANSFORM

One Read, Four Tools

Explained from the beginning, with nothing assumed. An architect draws a system once. Teamcenter keeps the master copy. From that one master copy, three completely different engineering tools each get the drawing they need — and none of them holds a second copy of anything.

The idea in one picture

Start with the problem in the plainest terms. A fuel system is one thing, but four different people need four different pictures of it. The architect wants boxes and lines. The electrical engineer wants wires and connectors. The fluid engineer wants pipes, pumps and valves. The reliability engineer wants to know how it breaks. Traditionally each of them draws their own picture, and the four pictures drift apart the moment anyone changes anything.

The forward transform removes the drift by removing the copies. There is one master description in Teamcenter. Every downstream picture is generated from it.

1 Cameo (SysML) The architect draws the skeleton: 12 blocks, 22 plugs, 11 wires. "What exists, and what is joined to what." push 2 Teamcenter The one master copy. Every part gets a permanent ID (041908, 041948 …). "The filing cabinet everyone reads from and writes to." one read 3 Sorter reads the plugs Capital wires, signals, connectors the electrical drawing NX Schematic Designer pipes, pumps, valves, tanks the fuel / hydraulic drawing MADe parts, functions, flows the "how does it break" model THE RULE THAT DECIDES A part goes to a tool when it has a plug of that kind. The boost pump has fuel + power + signal plugs, so it goes to all three. NOTHING IS COPIED TWICE Three tools, three drawings, one part. Change it in Teamcenter and all three change.
One master description in Teamcenter, three generated pictures. Nothing is copied twice — change the master and all three change.

The rule that decides where each part goes

The interesting question is step 3: when the sorter reads Teamcenter, how does it know that a pump belongs on the fuel drawing and the electrical drawing, but a pressure sensor belongs only on the electrical one?

The answer is the part's ports — its plugs. Every plug is typed by an interface: fuel, electrical, or signal. A part reaches a tool when it has a plug of that kind. Nobody maintains a list; the design itself already says it.

THE SCOPING RULE, IN ONE PICTURE ElectricBoostPump Teamcenter item 041948 one part, one identity, seen by three disciplines fuelIn powerIn cmdIn fuelOut Every plug has a kind fluid — fuel, oil, hydraulic electrical — power signal — commands, sensing NX Schematic Designer because it has a fluid plug Capital because it has an electrical plug Software because it has a signal plug And the reverse works too FuelPressureSensor has only signal plugs, so no pipe is drawn for it in NX. Nobody had to write that down: the plugs said so.
The scoping rule: a part reaches a tool when it has a plug of that kind. The design already says it, so nobody maintains a list.
Why this rule and not composition The first proposal was to scope by structure — "everything under the fuel assembly goes to NX". That answers a narrower question (once you are inside NX, which sheet does this go on) and it gets multi-domain parts wrong, because a boost pump genuinely belongs to three disciplines at once. Ports scope correctly and they generalise past NX.

Here is the rule actually running, against the live Teamcenter tier, with no model file involved at all:

$ node bin/route-from-tc.mjs --item 041908

ROUTING DERIVED FROM TEAMCENTER 041908 (no Cameo model read)

  CheckValve               fluid                      -> nx-diagramming
  ElectricBoostPump        electrical+fluid+signal    -> capital, nx-diagramming, software
  Engine                   fluid                      -> nx-diagramming
  FlopTube                 fluid                      -> nx-diagramming
  FuelControlUnit          electrical+signal          -> capital, software
  FuelFilter               fluid                      -> nx-diagramming
  FuelPressureRegulator    fluid                      -> nx-diagramming
  FuelPressureSensor       signal                     -> capital, software
  FuelQuantitySensor       signal                     -> capital, software
  HeaderTank               fluid                      -> nx-diagramming
  MainFuelTank             fluid                      -> nx-diagramming

  ports typed via Seg0Implements: 22   untyped: 7

The seven untyped ports are correct and expected: they are activity parameter pins on the functions (BoostFuelPressure, StoreAndCollectFuel …), not block ports. An audit that reported them as failures would be lying.

Where the typing lives, and the mistake worth recording

A port in Teamcenter is a first-class object of type Fnd0LogicIntrfce — display name "Logical Port", 792 of them on this tier. Its typing link to an interface is the relation Seg0Implements.

A correction, kept on the page because the lesson is general This work first concluded "ports are not objects in Teamcenter and the typing is gone." That was wrong. The error was reading the BOM occurrence view, where a port appears as a GDELine whose tag equals its own BOM-line uid, and concluding there was no object behind it. An occurrence is a port's usage; the object is separate — exactly as a component's occurrence differs from its revision. Check a type by name before declaring something absent.

Two API traps sit behind that link and both fail quietly:

TrapWhat happens
Seg0Implements looks like a propertyIt appears in the type's property list, but it is a GRM relation. setProperties on it returns HTTP 200, no error, and changes nothing. Use Core-2006-03-DataManagement/createRelations.
Resolving a port BOM line to its objectOnly bl_line_object works. awb0UnderlyingObject, bl_rev_object and bl_item all return nothing — which reads like "no object exists".

bin/link-port-interfaces.mjs populated all 22 block ports of item 041908 against their interface revisions (FuelInterface, ControlDataInterface, PowerInterface), dry-run by default, every write re-read to confirm. That is why the routing above works from Teamcenter alone.

What actually comes out

Three generators consume the same exchange bundle. They are deterministic, dependency-free, and contain no LLM — the same input produces byte-identical output every time.

GeneratorProducesConsumed by
capital-import-xml.mjsCapital Systems Architect project XMLCapital: Files → Import Project & Generate Diagrams
nx-schematic-spec.mjsan NX build spec, then a real .prt + PDFNX Schematic Designer
made-import-json.mjsa MADE API 2.0.0 payloadMADe: Integration → Import New Project

The whole engine is covered by 606 assertions across 29 suites in npm test, all passing as of 1 August 2026.

What this page does not claim

The forward direction is proven end to end on a real model. Two things are genuinely incomplete and are documented rather than glossed:

  • Function allocation does not travel. The bundle carries the functions but allocations is empty, so MADe synthesizes interface functions instead of landing the real ones. See the MADe page for exactly what that looks like in the product.
  • The port typing has not been wired into the bundle yet. It exists in Teamcenter and route-from-tc.mjs reads it, but a live read through the occurrence path still returns interfaceId: null. See the status board.
  • Every port arrives twice, and that breaks the propagation graph. A Cameo push files each block under two parents, so the occurrence read returns 44 port rows for 29 real ports and only 11 of the 44 flows end up carrying a connection. MADe's validation reports 55 errors as a result — measured and explained here.

The full, itemised done-and-not-done list is on its own page, because a documentation site that only lists successes is not worth reading.