TeamcenterKnowledge

Skills

TC BOM Structure

Skill tc-bom-structure. Read and build Teamcenter product structure over SOA. The working three-call sequence for BOM windows and occurrence trees (createOrReConfigureBOMWindows, expandPSAllLevels, connector endpoint properties), the proven occurrence child-add write, and why an empty 200 here means wrong request shape before it means deprecation. Use for BOM, occurrence, connectivity or structure work.

This is the area where 200 OK with an empty result has cost the most time. In this module that signature has meant wrong request shape more often than a dead operation, so rebuild the payload from the XSD before you go hunting for a successor. Read tc-soa-payload-shapes rule 2 for the deprecation case, and the correction at the bottom of this file for why it is the second thing to check here, not the first.

Reading structure: the proven three-call sequence

1. Open a BOM window

Cad-2019-06-StructureManagement/createOrReConfigureBOMWindows, struct CreateWindowsInfo3.

Prefer the 2019-06 operation: Cad-2007-01-StructureManagement/createBOMWindows is genuinely deprecated (TC 12.2, per the @Deprecated annotation), so 2019-06 is the right call on style grounds.

But this skill used to say 2007-01 was a dead silent no-op, and that was false. Retracted 2026-07-31, disproven live. Both bodies were sent to the same tier in one script, minutes apart:

Request Result
{"input":[{"itemRev":{...}}]} (the body the no-op finding was based on) 200 OK, output: []
correct {"info":[{...6 members + clientId...}]} real BOMWindow + BOMLine

The deprecated operation works. The original body had the wrong top-level array name (input instead of info) and was missing five of six required members plus both clientIds, so it could never have succeeded regardless of deprecation. It never tested deprecation at all.

Three earlier records had already said so, each stressing shape, and none was reconciled with the later "it is dead" write-up: harness-studio (2026-07-17, "createBOMWindows on RequirementSpec WORKS"), the plm-teamcenter agent profile ("works but REQUIRES the full info shape"), and capital-tc-integration ("REQUIRES full info shape incl revRuleConfigInfo/overrideFolders").

CreateBOMWindowsInfo (2007-01) requires item, itemRev, bomView, revRuleConfigInfo, objectForConfigure (singular, unlike 2019-06's objectsForConfigure) and activeAssemblyArrangement, plus clientId on the outer struct and the nested revRuleConfigInfo. Both unitNo: -1 / date: "" and unitNo: 0 / date: "0001-01-01T00:00:00Z" were verified to work.

CreateWindowsInfo3 is a strict sequence in which bomWindow, item, itemRev, bomView, revRuleConfigInfo, activeAssemblyArrangement and configContext are all required. Every inapplicable one must be sent as NULLTAG ({"uid":"AAAAAAAAAAAAAA","type":"unknownType"}), never omitted, never null. Nested RevisionRuleEntryProps additionally requires the date attribute even when today: true.

The top-level array is info, not input, and clientId is required on BOTH CreateWindowsInfo3 and its nested revRuleConfigInfo. Getting either wrong returns 200 OK with output: [] and no error, which is indistinguishable from a dead operation. This was hit and fixed live; see the correction below.

{"info":[{"clientId":"w1",
  "bomWindow":NULLTAG, "item":{"uid":"<Item>"}, "itemRev":{"uid":"<ItemRevision>"},
  "bomView":NULLTAG,
  "revRuleConfigInfo":{"clientId":"w1","revRule":NULLTAG,
    "props":{"unitNo":0,"date":"0001-01-01T00:00:00Z","today":true,
             "endItem":NULLTAG,"endItemRevision":NULLTAG,"overrideFolders":[]}},
  "objectsForConfigure":[], "activeAssemblyArrangement":NULLTAG,
  "configContext":NULLTAG, "effGrpRevList":[], "bomWinPropFlagMap":{}}]}

Returns output[0].bomWindow (the BOMWindow) and output[0].bomLine (the top line you expand from).

Print the exact member list any time:

python scripts/soa_lookup.py createOrReConfigureBOMWindows

2. Expand the occurrence tree

Cad-2007-01-StructureManagement/expandPSAllLevels

{"input":{"parentBomLines":[{"uid":"<BOMLine uid>","type":"BOMLine"}],
          "excludeFilter":"None"},
 "pref":{"info":[],"expItemRev":false}}

On item 041390 this returned 26 named Fnd0LogicConnRevision connector objects matching exactly the item-id range visible in the rich client, over plain SOA REST.

Reading the response: parent and each entry of children are WRAPPER structs, not ModelObjects. The uid lives one level down at .bomLine.uid:

output[i].parent.bomLine.uid          <- NOT output[i].parent.uid
output[i].children[j].bomLine.uid     <- NOT output[i].children[j].uid

output is flat: one entry per node in the whole subtree, each listing that node's direct children. To get the direct children of the line you asked for, match output[i].parent.bomLine.uid against your own top-line uid rather than assuming output[0] is it. Reading .uid at the top level silently yields None for every row, which looks exactly like an empty structure.

The expand's modelObjects do not carry bl_line_name / bl_item_item_id. Follow with getProperties on the BOMLine uids to name the lines.

BOMLine uids (BOM::nnnnnn) are per-window and per-session. They change every time you reopen, so never cache them across calls.

3. Resolve connector endpoints

expandPSAllLevels gives connector NODES but not which two ports each joins. Item-level GRM on the connector's Fnd0LogicConnRevision carries no endpoint data either (only Seg0Implements to the carrier and IMAN_master_form).

The answer is on the connector's occurrence (its BOMLine uid from the expand, not its item revision). Port occurrences are type GDELine (base BOMLine), and carry two plain properties:

fnd0bl_connected_end1   -> the BOMLine uid of the port at one end
fnd0bl_connected_end2   -> the BOMLine uid of the port at the other end
bl_connected_to_absName -> the full human-readable path for both ends

One getProperties call per connector. Confirmed on connector 041482: Comms/Modem.dataIf.1 to Comms/Transceiver.dataIn.1.

Found by running getTypeDescriptions2 on GDELine rather than by guessing.

A real negative, for contrast

Mdconnectivity-2014-10-MDConnectivity/findConnectionsOnPort looked exactly right by name and struct shape, but its core type Mdc0ConnectionElement does not exist on this deployment per getTypeDescriptions2. That module simply is not installed. That is a genuine "not on this tier" result, established with a type check rather than a fault code.

Writing structure: occurrence child-add WORKS

Bom-2025-06-StructureManagement/addOrUpdateChildrenToParentLine

Proven live on TC 2506 (2026-07-31): added a child to a real assembly and confirmed it by re-expanding, direct children 5 -> 6 and tree 22 -> 23 nodes. The response returns the new BOMLine in itemLines[0].bomline.

{"inputs":[{
  "parentLine":{"uid":"<top BOMLine uid>","type":"BOMLine"},
  "viewType":"",
  "items":[{"clientId":"add1",
            "occType":"",
            "usageRevisionType":"",
            "preAllocatedPsOccThreadUid":"",
            "item":{"uid":"<child Item uid>"},
            "itemRev":{"uid":"<child ItemRevision uid>"},
            "bomline":{"uid":"AAAAAAAAAAAAAA","type":"unknownType"},
            "itemLineProperties":{}}],
  "itemElements":[]}]}

usageRevisionType and preAllocatedPsOccThreadUid are the two required attributes the 2025-06 struct adds over the older one. bomline is NULLTAG when adding (it identifies an existing line when updating).

Full round trip verified end to end: add -> saveBOMWindows -> closeBOMWindows -> fresh session sees the line -> removeChildrenFromParentLine -> save -> fresh session back to the original 5 children.

Bom-2008-06-StructureManagement/removeChildrenFromParentLine
  {"bomlines":[{"uid":"<BOMLine uid>","type":"BOMLine"}]}
Cad-2008-06-StructureManagement/saveBOMWindows
Cad-2007-01-StructureManagement/closeBOMWindows
  {"bomWindows":[{"uid":"<BOMWindow uid>","type":"BOMWindow"}]}

You cannot verify BOM persistence by reopening in a new session

This is the trap that matters most here, and it produced a wrong finding earlier in this very investigation.

An add that has not been saved still shows up when you open a brand-new BOM window in a brand-new login. It even survives closeBOMWindows without a save. The obvious inference, that the write auto-committed, is wrong: those unsaved changes live in the pooled tcserver process, and a later login that lands on the same pooled server sees the modified BVR as though it were real. Three such "persisted" lines vanished when the server-manager pool was restarted for maintenance, which is what exposed the illusion.

So:

  • saveBOMWindows is what commits. Unsaved is uncommitted no matter how convincingly a re-open shows otherwise.
  • A re-open in a new session is not proof of durability, only proof the change is in the pool. There is no cheap client-side way to distinguish the two, so save explicitly and do not reason from the reopen.
  • Always closeBOMWindows. Leaked pooled windows accumulate, and enough of them will exhaust the pool (symptom: routing: Proxyrequest failed to connect, then hard TCP timeouts). They can also hold locks on items, blocking deletes until the pool recycles.

Correction: the old "adds nothing" symptom was request shape, not deprecation

This operation was recorded for months as "parses but silently adds nothing," and that was later attributed to deprecation because the Services Reference names a 2025-06 successor. That attribution was wrong. The deprecation is real, but it is not what produced the empty result.

A malformed request produces a byte-for-byte identical signature to a dead operation: 200 OK, empty result array, no fault, no message. That was reproduced live in this same session on createOrReConfigureBOMWindows (see the info vs input trap above), where correcting only the request shape turned a permanently empty output: [] into a working BOMWindow.

This mistake has now been made at least three times in this codebase, which is why it is worth a section rather than a footnote:

Operation Blamed on Actual cause Status
Bom-2008-06 addOrUpdateChildrenToParentLine deprecation request shape (2 missing attributes) write proven live
Cad-2007-01 createBOMWindows deprecation request shape (one-field body, wrong array name) disproven live, deprecated op works
createSchedule "Schedule Manager dead over REST" unset SiteTimeZone site preference fixed

In every case a 200 OK with an empty body was read as "this capability does not exist here," and in every case the capability existed. The failure mode is not ignorance of the API, it is treating an empty success as a diagnosis.

The createBOMWindows entry is the clean experiment: malformed body and correct body sent to the same tier minutes apart, output: [] versus a real BOMWindow. Deprecation did not stop it from working. So "the Services Reference says deprecated" is not on its own a reason to expect an empty result.

So when a structure call returns 200 OK with nothing in it, the order of investigation is:

  1. Rebuild the payload from the XSD sequence first. Every required member present, correct top-level array name, clientId at every level that declares it, NULLTAG rather than omission or null.
  2. Check site preferences and session context (project/program, timezone).
  3. Only then suspect deprecation.

Shape is the cheapest hypothesis and has been the correct one every time so far. tc-soa-payload-shapes rule 2 still holds for genuinely dead operations, but an empty 200 is not by itself evidence of one. Before recording any operation as a dead no-op, paste the exact request body into the finding. Every one of the misdiagnoses above would have been caught on sight if the body had been written down next to the conclusion.

createOrUpdateRelativeStructure faults, and this one is real

Run live 2026-07-31, both versions, against the same parent/child that addOrUpdateChildrenToParentLine handles fine:

  • Cad-2007-01-... -> 214022 JSON parsing.
  • Cad-2025-06-... -> 214007 "An error occurred in DOM parsing", a gateway-level marshalling failure.

Five shape variants of the 2025-06 call (lastModifiedOfBVR empty vs ISO date, bomViewTypeName "view" vs empty, with and without moveInfo) all returned the identical 214007. Invariance across value changes points at the struct itself, probably the cross-namespace imp2:MoveInfo / OccThreadEquivalent nesting, not at anything callable from the client side.

This is a genuine fault, not the misdiagnosis pattern: it is a hard HTTP 500 with a fault code, not a 200 OK with an empty body. Unresolved, and not worth more effort, because addOrUpdateChildrenToParentLine does the job.

Other structure operations: saveBOMWindows is Cad-2008-06.

The alternative that already works

For functional and logical decomposition, the Seg0Realize relation is proven, semantically correct, and needs no BOM window at all. BOM is for physical product structure. A root Fnd0LogicalBlock item named <PROJECT>-LBOM with component occurrences is the proven logical-structure container pattern. See tc-relations-traceability.

Requirement spec structure is occurrence structure too

Placing a requirement INTO a spec (so it shows as a numbered line rather than a free-floating item) is Internal-ActiveWorkspaceBom-2025-06-OccurrenceManagement/addObject5, with the spec's occurrence BOMLine as parentElement (type Arm0RequirementSpecElement), objectsToAddList[].objectToAdd set to the requirement Revision uid, and productContext set to the spec's Awb0ProductContextInfo BOMLine. Those SR::N::... uids come from the AWC URL's c_uid/pci_uid or from a spec-structure expand.

That operation is not in the SDK's WSDL kit (it is AWC-internal). It was captured verbatim from the AWC's own network traffic and has not been independently replayed through a raw SOA client. Treat it as documented, not proven. See tc-capture-awc-calls.

★ Reading logical blocks + ports out of expandPSAllLevels

Three things about the returned rows will each hand you a clean-looking zero or a double-count instead of an error. Verified live on item 041908 (2026-08-05).

1. Blocks and ports are typed on DIFFERENT fields. Match both or you get nothing:

ports  -> itemType "Logical Port",  underlyingType null    (no underlying Item; class GDELine)
blocks -> itemType null,            underlyingType "Fnd0LogicalBlockRevision"

Filtering blocks on itemType alone returns 0 rows and no error.

2. Rows are OCCURRENCES, so dedupe by object. 041908 returns 23 block occurrences for 12 block objects and 58 port occurrences for 29 port objects — the same object used under more than one parent. Collect by bl_line_object, but keep a bomLineUid -> objectUid index as well, because connector endpoints (fnd0bl_connected_end1/end2) are occurrence uids and will not resolve against object uids. Occurrence names also carry an instance suffix (fuelOut.1); the object's object_name does not.

3. Function pins are also "Logical Port". A port's parent tells you which architecture it belongs to — Fnd0LogicalBlockRevision (logical) vs FunctionalityRevision (functional). On 041908 that is 44 vs 14 occurrences. Without the parent check, function pins look like untyped block ports and domain coverage reads 22/29 instead of the true 22/22.

Port domain itself is not a property on the port: it is port -> Seg0Implements -> Seg0Interface, then interface name -> your own registry.

Related skills

tc-soa-payload-shapes, tc-soa-docs-navigation, tc-capture-awc-calls, tc-relations-traceability.


Generated from skills/tc-bom-structure/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.