Skills
TC Classification Hierarchy
Skill
tc-classification-hierarchy. Build the Teamcenter Classification TREE ITSELF - the class/hierarchy nodes, not the placements into them. Three ways in (the documented SOA op, Classification Manager's Add Class panel, its JSON/PLMXML Import), which one works when, the account trap whose error message reads like a wrong-data-model conclusion, the four HierarchyNodeDetails fields whose XSD prose is misleading, and why there is no safe undo. Use before any classification bulk-load when the target branch does not exist yet, and for designing a new taxonomy.
The companion to tc-classification-bulkload. That skill loads ICOs (placements) into classes
that already exist. This one is about making the classes.
Domain-independent: the F-35 run built a Standard Notes tree, the next built a Signals taxonomy. The mechanics do not change with the domain; only the breadcrumb source does.
Do the mapping before you create anything
Design the tree against real items and map them to it on paper first. This is not ceremony: on the Signals run, mapping 16 live signals onto a draft taxonomy found two modelling defects before a single node existed - an item typed as a Signal that actually conveyed fuel (a mass flow, not information), and a command signal declared on the wrong interface. Neither was a gap in the taxonomy. Both were the taxonomy telling the truth about the model.
A node you create is effectively permanent (see "There is no undo"), so the cheap moment to be wrong is before the first create, not after nineteen.
Design guidance that has held up twice: if items are classified along two genuinely independent
axes, make both real branches rather than nesting one inside the other, and let multiple
classification (allowMultipleClassification: true) put an item in one class of each. Nesting
forces re-classification when the subordinate axis changes even though the item's meaning did not.
Three ways in, and when each works
1. SOA: ClassificationCore-2013-05-Classification/createOrUpdateHierarchyNodes
The documented op, found by grepping the Help Server WSDL kit
(ClassificationCore1305Classification.xsd), not by guessing service names - a first blind guess of
ClassificationCore-2013-05-ClassificationCore/... used the wrong domain segment and faulted with a
generic syntax error indistinguishable from "no such operation". The real domain segment is
Classification, matching the XSD's own namespace.
{"hierarchyNodeDetails": [{
"nodeToUpdate": NULLTAG, // NULLTAG = create mode
"parent": {"uid": "<parent NODE_UID>", "type": "unknownType"},
"masterNode": NULLTAG, "icon": NULLTAG, "images": [], "attachments": [],
"nodeId": "<id>", "nodeName": "<name>", "nodeDesc": "<desc>",
"nodeType": "HierarchyNode_Master", // Group/Master/Reference; Group untested
"storageClassTypeName": "", // empty even for a Storage Class
"isLeafNode": false, "levelSortIndex": -1,
"isAbstract": true, // true = Abstract Class, false = Storage Class
"isAssembly": false, "allowMultipleClassification": true, "instanceCount": 0
}]}
The parent's uid is the existing node's NODE_UID property, readable from
findClassificationInfo3's clsClassDescriptors[...].properties - the same read used to resolve
classes for placements, no extra lookup.
The new node's uid comes back in the top-level nodeObjects array (one per input entry, in
order), not under ServiceData.created.
Four fields whose XSD prose misleads. All corrected by reading a real existing node back with
getHierarchyNodeDetails rather than reasoning about the schema:
storageClassTypeNamelooks like a type name. A first guess of"Cls0ClassBase"faults withclass Cls0ClassBase cannot be found(132008). A real Storage Class node's value is its own numeric class id - self-referential, and it does not exist until after creation. Leave it empty; it populates itself.isLeafNodereads backfalseon a real, genuinely terminal Storage Class. It is not creation intent. Leavefalse.levelSortIndexreads back-1, not a sibling ordinal. Do not compute sibling ordering.isAbstractis the only field that actually distinguishes Abstract from Storage.
2. Classification Manager (Active Workspace) - the Add Class panel
Works as the logged-in user, which matters when the SOA route is refused (below).
Select the parent node in the tree, then New -> Add Child (or Add Sibling). The panel asks for, in order:
| Field | Values |
|---|---|
| Class Type | Blank, Group, Abstract Class, Storage Class |
| ID | required, must be unique |
| Name | required |
| Parent | shown read-only, from the tree selection |
| Unit System | Blank, Metric, Non-Metric, Both |
Add stays disabled until all required fields are set, and success shows
Class "<name>" definition created. Verify from the Details panel (ID, Class Type, Is Abstract,
parent) rather than the toast.
Cost: roughly six interactions per node. Fine for a handful, painful past a dozen.
3. Classification Manager Import - JSON or PLMXML
The Import button takes a JSON or PLMXML file through a native file picker. This is the one-shot route for a whole tree and the right answer for anything past a handful of nodes.
Two things to know before planning around it:
- The picker is a native OS dialog. Browser automation cannot drive it; you need desktop control or a person to choose the file.
- There is no Export to learn the schema from. The
...overflow menu's Import/Export submenu offers only "Import Vendor Hierarchy". Get the JSON/PLMXML schema from the Help Server kit, not by round-tripping an existing class.
★ The account trap, and the wrong conclusion it invites
Node creation needs a DBA-privileged account, the same "Active Admin" boundary as the Classification Manager UI. The documented symptom is a clean privilege fault, code 51057.
It does not always present that way. Running as a non-DBA service account against a tier whose
tree was created by infodba, the identical request - same parent NODE_UID, same body, same tier -
faults instead with:
7023 Given smlb0 when expecting N10Teamcenter14Classification21Cls0HierarchyNodeI
That reads as a data model error: "this tree is made of legacy SML classes, so the Cls0 operation
does not apply here". Every class on the tier also reports CLASS_OBJECT_TYPE: SMLClass, which
corroborates the wrong story beautifully. The conclusion is wrong. The same op, same parent, same
tier had already worked under infodba.
Before concluding a tier's classification tree is the wrong model for this operation, re-run the identical call as a DBA. A type error is not always about types.
Placements: use the PUBLIC op, not the AW-internal one
The F-35 reference implementation writes placements with
Internal-IcsAw-2018-12-Classification/saveClassificationObjects2, an undocumented AW-internal
endpoint. Copying that is a trap worth naming, because there is a public, documented operation in
the same service as the hierarchy op:
ClassificationCore-2013-05-Classification/createOrUpdateClassificationObjects
classificationObjectInfos: [{
objectId: "<id, create only>",
objectToUpdate: NULLTAG, // create mode
nodeRef: {uid: "<CLASS NODE_UID>"}, // the node uid, NOT the class-id string
classifiedObjectRef: {uid: "<item uid>"},
propValues: [{name, values[]}]
}]
Note nodeRef takes the class's NODE_UID (readable from findClassificationInfo3), not the
CLASS_ID string that the AW-internal endpoint wants. That difference alone will send you in
circles if you assume the two APIs are interchangeable.
★ The lesson underneath it: the local Help Server WSDL kit had this the whole time and was not
consulted, because an existing script in the repo used the internal endpoint and that felt like
precedent. A working script is evidence that something CAN work, not evidence that it is the
supported path. Grep wsdls/*.xsd for the capability before copying a call shape from code -- see
tc-soa-docs-navigation.
On saber2506, saveClassificationObjects2 refuses every create shape tried
(asking isLoaded on NULLTAG, code 65, with clsObject NULLTAG and omitted; the 2019-12 version
rejects the same body as invalid syntax), and the public op returns 214022 parse errors until the
body matches the XSD exactly. After two or three failed shape guesses, stop guessing and capture
what Active Workspace itself sends -- tc-capture-awc-calls exists for precisely this.
The plmxml plus plmxml_import route remains the officially supported one for bulk, and is the only
one that rebuilds the search index.
★ Placements on a CLASSIC tree: the op that actually works
On a classic (SMLClass) tree, neither of the two obvious candidates is the answer:
| op | result on saber2506 |
|---|---|
Internal-IcsAw-2018-12.../saveClassificationObjects2 |
asking isLoaded on NULLTAG (65), every create shape |
ClassificationCore-2013-05.../createOrUpdateClassificationObjects |
214022 parse errors; wants a Cls0 node uid |
Classification-2007-01-Classification/createClassificationObjects |
works |
The classic-era op is the one that matches a classic tree, because it takes classId as the plain
string the tree uses rather than a node uid:
{"clsObjs": [{
"clsObjTag": NULLTAG, // create
"wsoId": {"uid": "<item uid>"}, // the object being classified
"properties": [],
"instanceId": "", "classId": "SIGFCMD01",
"unitBase": "METRIC" // enum METRIC/ENGLISH/UNSPECIFIED
}]}
unitBase is an enum in caps. Lowercase "metric" fails as An error occurred in DOM parsing
(214007), which reads like a malformed body rather than a bad enum value.
Classification-2007-01 also has deleteClassificationObjects, so unlike hierarchy nodes,
placements are reversible. That materially changes how much caution a placement run needs.
The prerequisite that produces a clear error
The type must be listed in the ICS_classifiable_types site preference or every create fails:
71188 In order to classify the Workspace Object "X", please ensure that its type
"Seg0IntfSpec" is listed in the preference "ICS_classifiable_types".
That is an unusually good error message. Take it at face value; it is the whole blocker.
★★ Site preference writes SILENTLY NO-OP without privilege
Adding the type needs a DBA. Without one, on this tier, three different operations all report success and change nothing:
Administration-2012-09.../setPreferencesAtLocationsAdministration-2012-09.../setPreferences2Administration-2007-06.../setPreferences
All returned no partial errors. A getPreferences read straight afterwards showed the value
completely unchanged. There is no fault, no privilege code, no warning.
Always read the preference back after writing it. "No partial errors" from a preference write is not evidence of anything, and reporting it as done is exactly the mistake this note exists to prevent.
The search index makes "already exists" unreliable
Same caveat as REST placement writes. A node created by any of the three routes is invisible to
findClassificationInfo3 until smlutility -create_indexing_views rebuilds the index. Confirmed
live: querying a just-created node by name returned zero matches while a direct getProperties on
its uid confirmed it fully exists.
Consequences:
- Within a run, track new nodes from the create call's own
nodeObjectsresponse. Never re-query to "confirm" a node you just made. - Across runs, an existence check can wrongly report a previously-created node as missing, so a
re-run risks duplicate creates. Get
smlutility -create_indexing_viewsrun after an--applybefore trusting idempotency. - Verify with
getPropertieson the returned uid. That bypasses the index and is the only read that answers honestly straight after a create.
There is no undo
Core-2006-03-DataManagement/deleteObjects does not remove a Cls0MasterNode: the call returns
no error and the object is still fully readable afterwards. No dedicated removal op has been found.
So:
- Name anything experimental unmistakably (
*_DELETE_ME_*) and clean it up through the Classification Manager UI. - Get the ID convention right the first time. Match the site's existing style rather than inventing
one: on a tier whose fixed roots read
ENGICM01/STDPRTICM01, a new branch under Engineering follows asSIGICM01,SIGFNICM01, and so on. Deeper custom classes on the same tier use opaque numeric ids, so both conventions coexist and either is defensible - but you only get one shot. - Create top-down. A child needs its parent's uid, so a failed parent blocks everything under it;
report those as
blocked_on_parentrather than attempting the child.
Abstract or Storage
Heuristic that matches every existing tree observed: a node that is a prefix of a longer path is
organizational (Abstract Class); a true leaf holds ICOs (Storage Class). Groups sit above both
and are what the fixed roots (SAM, ICM, ENGICM01) are.
Only Abstract and Group variants have been live-tested via SOA. Storage Class has been created through the UI.
Reference implementation
Siemens/f35-notes-classification/build_hierarchy_plmxml.py - reads a breadcrumb spreadsheet,
diffs against live, creates only what is missing, --apply gated, writes a report. Shares
tc_client.py with the placement stage. Fork it and change only the sheet name, the column, the
path separator and the root id.
Related
tc-classification-bulkload (the placements that go into this tree), tc-soa-docs-navigation (how
the op was found - grep every .xsd), tc-soa-payload-shapes (NULLTAG, the full-struct rule),
tc-verify-and-cleanup (never report a node a call did not return).
Generated from skills/tc-classification-hierarchy/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.