Skills
TC Relations Traceability
Skill
tc-relations-traceability. Create and verify Teamcenter relations (GRM) over SOA. createRelations shapes, the revision-uid rule, direction enforcement, the verified relation-type atlas for architecture/allocation/verification/reliability, and the one-call reference-property read that beats GRM traversal. Use when linking TC objects or proving a traceability claim.
An orphan item is not a deliverable. Author relation-structured sets.
The operation
Core-2006-03-DataManagement/createRelations
{"input":[{"clientId":"r1",
"relationType":"Seg0Allocate",
"primaryObject":{"uid":"<uid>","type":"<Type>"},
"secondaryObject":{"uid":"<uid>","type":"<Type>"}}]}
The XSD also marks userData (a ModelObject) required; in practice the JSON
REST binding accepts the call without it. Add userData as NULLTAG if a call is
faulting.
Two rules that cause most failures
- Relations must use REVISION uids, not Item uids. GRM rules are declared at
the revision level (
p=Fnd0LogicalBlockRevision, s=FunctionalityRevision).createRelationson item-level uids will not match the rule. One documented exception:Mq0ElementToFailureModeReltakes theMq0FailureModeitem-level uid as secondary. - Direction is strictly enforced, not just the type pair. Reversing a relation is explicitly rejected with a clear "not allowed" fault. GRM primary and secondary order is real.
A rejection can be informative rather than a bug. Seg0Allocate between
Fnd0LogicConnRevision and FunctionalityRevision is refused with "Allocate
relation is not supported between these two objects", confirming the GRM table's
silence on that pair was correct: Seg0Allocate's real declared pairs from a
connector are to NetworkRevision/PSConnectionRevision.
Verified relation atlas
Architecture and allocation
| Purpose | Relation | Primary | Secondary |
|---|---|---|---|
| Functional/logical decomposition | Seg0Realize |
FunctionalityRevision |
FunctionalityRevision (self-referential; same for Fnd0LogicalBlockRevision) |
| Allocation | Seg0Allocate |
Fnd0LogicalBlockRevision |
FunctionalityRevision |
| Connector realization | Seg0Allocate |
Fnd0LogicConnRevision |
NetworkRevision |
| Interface contract | Seg0Implements |
Fnd0LogicConnRevision |
Seg0IntfSpec |
| Port typed by transport | Seg0Implements |
Fnd0LogicIntrfce (the PORT object, not a revision) |
Seg0InterfaceRevision |
| Generic cross-domain trace | FND_TraceLink |
almost anything | almost anything |
Seg0Implements carries a second, different arrow, and it is the one that
closes port-to-protocol. EXERCISED live on vm2606 (TC 2606) 2026-08-09, 11
relations created and each read back by an independent getProperties after the
write:
{"input":[{"clientId":"p1","relationType":"Seg0Implements",
"primaryObject":{"uid":"<port uid>","type":"Fnd0LogicIntrfce"},
"secondaryObject":{"uid":"<interface REVISION uid>","type":"Seg0InterfaceRevision"},
"userData":{"uid":"AAAAAAAAAAAAAA","type":"unknownType"}}]}
Note the asymmetry, which is easy to get wrong: the port side anchors on the
plain object (a Fnd0LogicIntrfce, className GeneralDesignElement, which has no
revision), while the interface side anchors on the revision per the usual
Seg0Interface rule. Reach the revision via the item's revision_list.
Two facts about Fnd0LogicIntrfce worth having before you plan a port write:
- A port has NO
item_id. Its identity is uid plus type. Anything keying ports by id is keying on something that is not there; anything keying them by name is worse, because port names collide freely (25 Aircraft ports held five duplicated names plusp1five times). Seg0Implementsandfnd0Directionare both present-and-empty on a port landed by the HCL connector, on 25 of 25 measured. Present-and-empty is a different finding from absent, and only a read with a known-good control attribute (object_name) distinguishes them. The Cameo model's port-to- InterfaceBlock typing does not appear to survive the crossing, so this relation is currently the repair, not the readout.
Seg0Realize is the practical decomposition relation for functional and logical
structure. BOM occurrence child-add is a separate, harder path (see
tc-bom-structure), and BOM is for physical product structure anyway.
FND_TraceLink is foundation-level and broadly permissive. It worked
Signal -> Fnd0LogicalBlock, HRN_Cable Revision -> SignalRevision, and
Fnd0LogicConnRevision -> SignalRevision, in some cases without a declared GRM
row backing it.
Verification lifecycle
Every arrow below was created live and read back:
Requirement <--Seg0Derive-- IAV0VerifReqmt (what and how to verify)
Requirement <--Seg0Satisfy-- IAV0TestCase (how it WILL be verified)
Crt0VldnContract --IAV0VerificationTL--> IAV0SimulRequest (simulation path)
Crt0VldnContract --IAV0VerificationTL--> IAV0TestRequest (physical-test path)
IAV0TestRequest --IAV0VerificationTL--> IAV0TestProcedur
IAV0TestProcedur --IAV0VerificationTL--> IAV0TestEvent (execution)
Both request paths can coexist on one contract: it is a multi-value reference
property. IAV0VerifAssmForm is where the verification method and result are
literally recorded; it is a Form and needs a different attach pattern.
Reliability
| Purpose | Relation | Primary | Secondary |
|---|---|---|---|
| Element to failure mode | Mq0ElementToFailureModeRel |
Fnd0SEBlockRevision family (FunctionalityRevision or Fnd0LogicalBlockRevision) |
Mq0FailureMode item uid |
| Function to failure condition | Fha0AnalyzedByFCRel |
FunctionalityRevision only |
Fha0FailureCndnRevision |
| Analysis to what it assesses | TC_CAE_Source |
CAEAnalysisRevision |
any assessed ItemRevision family |
Design consequence: the relation property lands only on the PRIMARY object, and
the assessed element is usually created by an earlier architecture task, not by
the reliability task. A reliability completion check therefore needs the touched
assessed-element uid too. createRelations reports it in ServiceData.updated,
so a runner harvesting all uids seen in tool results (not just brand-new creates)
covers it naturally.
Requirements
IMAN_specification is a real relation name, but it is not always the
containment relation. On production Requirement data it points at a FullText
dataset (the requirement's rich-content body), not at a parent spec. Spec to
requirement containment is the BOM/occurrence structure, not a GRM relation.
Confirm what a relation type actually connects on THIS instance, by inspecting a
real production object, before using it structurally.
Verifying a relation: the one-call read
Every GRM relation declared against a specific business-object type pair compiles into a same-named reference property on the primary object.
getProperties(revisionUid, attributes: ["Seg0Allocate"])
returns the allocated Function's uid and display name directly. No GRM traversal, no relation-object walk. This held for every one of roughly 15 relations tested across three cracking rounds. It is one call instead of two.
The exception you must plan around
Relations whose GRM primary type is the maximally generic WorkspaceObject
do not expose this way, on either endpoint, under any name.
Seg0Satisfy and Seg0Derive are both like this. They create successfully and
read back as nothing.
Fallback: createRelations returns the relation object's own uid (type
ImanRelation). getProperties on that uid returns a human-readable
confirmation naming both endpoints, for example
"039244/-/ESP-BCU Brew Controller ECU -> 039241/-/ESP-FN-1 Control Brew Temperature".
This requires the authoring pipeline to capture and carry that relation uid.
Any new domain crack that leans on a WorkspaceObject-primary relation should
assume it will hit this gap and either pick a type-specific alternative or plan
the relation-uid capture first. An honest "cannot verify yet" beats a check that
silently fails on correct work.
Reading a Seg0 relation: the db lane, and a fake-property control
EXERCISED 2026-08-12 on vm2606 (TC 2606) and saber2506 (TC 2506).
Two things will make a correct read look like an empty one.
1. The ui lane can be empty while db holds the uid. Measured on a real
Fnd0LogicConnRevision:
Seg0Implements ui:[""] db:["gQJAAEBhp$kOEC"] <- the uid is ONLY in db
-> Seg0ItemFlowExchanges
Seg0HasExchangeItem ui:["001360-ZX5_Sig"] db:["Q4DAAEBhp$kOEC"]
A reader gating on ui reports "no item flow" with an HTTP 200 and no error. Worse,
that intermediate Seg0ItemFlowExchanges object has object_string empty in both
lanes, so a reader keying on the display string sees nothing even in the right lane.
Chase the db uid and dereference it.
2. Ask for a property you know does not exist, in the same call. This is what turns an empty result into information:
| Response shape | Means |
|---|---|
{"ui":[], "db":[]} |
the property exists on this type and is genuinely unpopulated |
| omitted from the response entirely | the property does not exist on this type |
Without the fake-property control those two are indistinguishable, and "absent" gets
reported as "empty": the scope-error family the workspace CLAUDE.md documents.
Measured with Seg0NotARealProperty alongside the real ones.
Read the REVISION, not the item. On the item, a real-but-unpopulated relation and a fake name are both omitted, so an item-level read discriminates nothing.
It differs by release, so label the release
| 2606 (vm2606) | 2506 (saber2506) | |
|---|---|---|
Seg0Implements on the revision |
returned | returned |
Seg0Allocate on Fnd0LogicalBlockRevision |
returned (empty) | omitted, not a property of the type |
Seg0Realize |
returned | omitted |
So on 2506 a getProperties-based allocation read is impossible by construction,
and its absence from a read is not evidence about the data. Any "confirmed readable"
note must carry the release it was confirmed on: an unlabelled one travels, and the
next reader applies it to the tier where it is false.
Do not default to GRM traversal for verification
expandGRMRelationsForPrimary / ForSecondary do work on some instances (proven
2026-07-28 on saber2506, and they are how the Cameo signal-to-carrier chain was
read) with body:
{"primaryObjects":[{"uid":"<uid>"}],
"pref":{"expItemRev":false,"returnRelations":true,
"info":[{"relationTypeName":"","otherSideObjectTypes":[]}]}}
But whereReferenced, whereReferencedByRelationName, and getRelatedObjects
have faulted on multiple unrelated instances. Treat any GRM-traversal fault on a
new instance as expected-until-proven-otherwise, not as a struct mistake to
debug. The reliable set on every instance tested: getProperties,
executeSavedQuery, createRelations, deleteRelations, deleteObjects.
Also: Core-2007-01-DataManagement/loadObjects with a bare {"uids":[...]} faults
214086 "invalid syntax". Use getProperties.
Do not prove absence with the rich client
Impact Analysis at rule "All" and the Details tab both showed nothing for a pin
that demonstrably had a Seg0Implements relation, which SOA returned immediately.
An empty relation panel means the view is not configured to traverse that
relation, not that the relation is absent.
Bidirectionality
A trace link in one direction is necessary but not sufficient to describe a requirement as "traced" in a report. Confirm the link is queryable from the end you are claiming coverage from, before writing coverage language.
Related skills
tc-object-authoring, tc-verify-and-cleanup, tc-query-discovery.
Generated from skills/tc-relations-traceability/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.