Skills
TC Requirement Spec Content
Skill
tc-requirement-spec-content. Put requirements INSIDE a Teamcenter specification so Active Workspace, the Content tab, exports and Product Configurator can all see them. Covers the two different things "in a spec" can mean and why having only one of them looks like success, the two undocumented Active Workspace calls that actually place content (getOccurrences4 then addObject5), the five payload members whose absence returns a fault naming nothing, and the verification mistake that makes an unpersisted structure report as built. Use whenever authoring requirements, verification requirements or any spec content, and before any trace link matrix or variant work.
Standard practice: a requirement is authored INTO a specification, never left loose. A requirement outside a spec has no document position, no numbering, cannot be exported to Word or ReqIF, cannot be baselined as a deliverable, and, the one that silently kills downstream work, cannot carry variant conditions, so Product Configurator can never filter it. Treat "which specification does this go in" as part of creating a requirement, not as a later tidy-up.
Run status: EXERCISED on vm2606 (TC 2606) 2026-08-15. Every claim below came back
from a call. Reference implementation: se-process-skills/demos/jpo-f35/ stage1b-verification-matrix/spec_content.py.
★★ "In a spec" means TWO different things, and having one looks like success
| carrier | what it drives | how to read it |
|---|---|---|
IMAN_specification relation |
Relations tab, Relations Tree/Graph | getProperties(specRev, ["IMAN_specification"]) |
| occurrences in the spec structure | Content tab, exports, trace link matrix, variant conditions | getOccurrences4 (below) |
They are independent. A specification can have all its requirements attached by
IMAN_specification and zero occurrences: the Relations tab looks perfectly
healthy, the Content tab shows only the root node, and a Full-Rollup trace link matrix
comes back empty.
That exact state existed on a demo tier for two days and was read three different wrong ways before anyone looked at both carriers:
- A BOM window plus
expandPSAllLevelsreturned 0 for a spec that had 22 requirements correctly attached. That zero was reported as "this spec has no structure", which was an instrument error, not a fact. - Later the same spec reported 22 from the same call. The reading changed; the data had not.
⇒ Before concluding anything about spec content, read BOTH carriers. One of them being empty tells you which half is missing, not that the spec is empty.
The two calls that place content
Neither is in the SOA WSDL/SDK kit. Both were captured from Active Workspace's own
traffic (see tc-capture-awc-calls) and then replayed headlessly.
1. Open the structure and mint the runtime ids
Internal-ActiveWorkspaceBom-2022-06-OccurrenceManagement/getOccurrences4
The only member that identifies the spec is inputData.product.uid, which is the spec
REVISION. Everything else is defaults and NULLTAGs, and every NULLTAG is required:
omitting them returns 214022 JSON parsing naming nothing.
{"inputData": {
"config": {"effectivityDate":"0001-01-01T00:00:00","unitNo":-1,
"productContext":NT,"revisionRule":NT,"occurrenceScheme":NT,
"sourceContext":NT,"changeContext":NT,"appliedArrangement":NT,
"closureRule":NT,"viewType":NT,"serializedRevRule":"",
"effectivityGroups":[],"endItem":NT,
"variantRules":[], <-- the Product Configurator slot
"svrOwningProduct":NT,"effectivityRanges":[]},
"cursor": {"startReached":false,"endReached":false,"startIndex":0,"endIndex":0,
"pageSize":250,"startOccUid":"","endOccUid":"","cursorData":[]},
"focusOccurrenceInput": {"element":NT,"cloneStableIdChain":""},
"filter": {"searchFilterCategories":[],"searchFilterMap":{},
"fetchUpdatedFilters":false,"recipe":[],
"searchFilterFieldSortType":"Priority","searchSortCriteria":[]},
"requestPref": {"expandedNodes":[],"includePath":["true"],
"loadTreeHierarchyThreshold":["50"],"savedSessionMode":["ignore"],
"startFreshNavigation":["true"],"displayMode":["Tree"],
"showExplodedLines":["false"],"calculateFilters":["false"],
"viewType":[""],"useGlobalRevRule":["false"],
"defaultClientScopeUri":["Awb0OccurrenceManagement"]},
"expansionCriteria": {"expandBelow":false,"levelNExpand":0,
"loadTreeHierarchyThreshold":0,"scopeForExpandBelow":""},
"sortCriteria": {"propertyName":"","sortingOrder":""},
"product": {"uid":"<spec REVISION uid>"},
"parentElement": "AAAAAAAAAAAAAA" <-- a bare STRING, not an object
}}
Response keys, pinned off a real 200 because the XSD does not declare them. Four plausible guesses at these names were all wrong:
| you want | it is called |
|---|---|
root element SR:: uid |
parentOccurrence.occurrenceId |
product context SR:: uid |
rootProductContext.uid |
| the children AW displays | parentChildrenInfos[].childrenInfo[] |
2. Place the object
Internal-ActiveWorkspaceBom-2025-06-OccurrenceManagement/addObject5
{"input": {
"addObjectIntent": "", "numberOfElements": 1, "fetchPagedOccurrences": true,
"sortCriteria": {"propertyName":"","sortingOrder":""},
"requestPrefMap": {"defaultClientScopeUri":["Awb0OccurrenceManagement"],
"displayMode":["Tree"],"structExpanded":["true"]},
"addObjectParentChildrenList": [{
"parentElement": {"uid":"<parentOccurrence.occurrenceId>",
"type":"Arm0RequirementSpecElement"},
"siblingElement": NT, "actualParent": NT,
"productContext": {"uid":"<rootProductContext.uid>",
"type":"Awb0ProductContextInfo"},
"structExpanded": true,
"objectsToAddList": [{
"createInput": {"boName":" ","propertyNameValues":{},"compoundCreateInput":{}},
"objectToAdd": {"uid":"<the REVISION to place>","type":"<its type>"}}]}]}}
★★ Those five siblings of addObjectParentChildrenList are NOT optional. A first
capture truncated them away; sending only the list returns 214022 JSON parsing, which
names nothing and reads like a malformed list.
★ parentElement and productContext are SR:: runtime ids, not database uids.
They are minted per session by call 1 and cannot be constructed, guessed, or reused
from an earlier run. A script that hardcodes one works once and then fails in a way
that looks like a permissions problem.
★★★ Verify from a SEPARATE PROCESS, not a second call
This is the mistake worth the whole skill.
Re-opening the structure after the writes and counting the children passes whether or not anything was committed, because the re-open runs in the same session and reads the same working context the writes were staged in. Committed and staged return identical counts.
That produced a confident, wrong "37 children, verified by re-open" report. The correct check is a new process with its own login:
python spec_content.py --profile vm2606 --spec-rev <uid> --add-all # session A
python -c "...open_structure(...)" # session B, fresh login
⇒ Generalise it: a re-read is only independent if it crosses the boundary the write might not have crossed. For a session-scoped working context that boundary is the process, not the call.
Other things that return success and do nothing
- Adding an object that is already a child succeeds silently and changes nothing. No error, no partial error. If your "already present" test is wrong you will re-add the same rows and the count will refuse to move while every call reports OK.
displayNamecomes back numbered (1 VM-MSP2-SR-001-DYNAMIC), so an exact-set membership test against your own names classes every row as missing. Substring match, or compare on the underlying uid.tc_find_itemsonly runs theItem Namesaved query. ARequirementSpechas no naming rule, so its id lives initem_idand a name lookup returns a barenFound 0that reads as "no such object". Run theItem IDquery too.
★★ A multi-property write fails as a UNIT and still reports success
setProperties sending four properties in one call, with one of them over its
maxLength, returned success, no partial errors, and stored NONE of the four. The
property that mattered silently kept its previous value.
The symptom is a read-back that disagrees intermittently, which looks exactly like a caching or replication lag, and treating it as one is the wrong fix. Measured on vm2606 2026-08-15: three description strings at 134 to 145 characters against a cap of 128 took the whole update down with them.
⇒ Checking the property you care about is not enough. Check every property in the same call, before writing, against caps read off the tier. And when a read-back disagrees, rule out a rejected write before reaching for "it must be cached".
Text fields truncate silently
object_desc on a requirement revision is 240 characters; the verification
assessment form's iav0VerifApproach is 240 and iav0VerifMethodDesc is 128. Over-long
text is cut without an error and a truncated description still looks like a description.
Read maxLength from getTypeDescriptions2 and check the composed string before
writing. enrich_rows.py in the reference implementation does this and refuses the run.
★★ A multi-item addObject5 call can silently double-write
Measured on vm2606, 2026-08-16: one addObject5 call placing two objects in a
single objectsToAddList array (both under one addObjectParentChildrenList
entry) reported numChildredAdded: 2 but actually created four occurrences —
two of each object, the second pair's displayName suffixed " x2" (Teamcenter's
own duplicate-disambiguation naming). The response itself hinted at this
(newElementInfos came back as two separate groups, each listing both objects)
but was ambiguous enough that trusting it at face value would have reported
success on broken data. Independently confirmed as real, committed duplication —
not a same-session display artifact — via getOccurrences4 from a fresh
session (numberOfChildren: 4) and cross-checked a second, independent way with
the raw BOM-window path (createOrReConfigureBOMWindows + expandPSAllLevels),
which also returned 4 distinct Fnd0RequirementBOMLine children.
⇒ After any multi-item addObject5 call, verify the raw occurrence count with
a second instrument (the BOM-window path below), not just by trusting
numChildredAdded or re-reading getOccurrences4 in the same session. If in
doubt, add objects one at a time in separate calls rather than batching
multiple items into one objectsToAddList.
Removing a duplicate or wrong occurrence
Spec structure is BOM occurrence structure under the hood, so the ordinary
physical-structure removal call from tc-bom-structure applies unmodified to
Fnd0RequirementBOMLine occurrences:
Bom-2008-06-StructureManagement/removeChildrenFromParentLine
{"bomlines":[{"uid":"<child BOMLine uid>","type":"BOMLine"}, ...]}
Takes the child occurrence BOMLine uid(s) directly, not the parent. Get those
uids from a BOM-window expandPSAllLevels read (below), not from the SR::
runtime ids getOccurrences4/addObject5 use — they're a different id space.
Must be followed by Cad-2008-06-StructureManagement/saveBOMWindows to commit
(unsaved changes survive a reopen in the same window pool but are not durable —
the same trap the tc-bom-structure skill documents for ordinary structure) and
closeBOMWindows to release the window. Verify by last_mod_date on the parent
item/revision advancing, and by re-reading occurrence count from a fresh session
afterward — same discipline as the write itself.
Cross-checking getOccurrences4 with the raw BOM-window path, used both to
catch the duplication above and to confirm the fix:
Cad-2019-06-StructureManagement/createOrReConfigureBOMWindows
{"input":[{"clientId":"win1","item":{"uid":"<spec revision uid>","type":"RequirementSpec Revision"},"bomViewType":""}]}
then Cad-2007-01-StructureManagement/expandPSAllLevels on the returned window
line. ⚠ A malformed shape here returns output: [], which reads exactly like
"structure genuinely empty" — before trusting an empty result, confirm the
payload shape against a call that's already worked in the same session, don't
conclude absence from one attempt.
★★ On TC 2512 the child rows carry NO underlying object uid. Only displayName.
EXERCISED 2026-09-02 on sgt-demo-sandbox.plmfederal.com (Teamcenter 2512,
25120.2603), placing 32 requirements into spec 034666. The recipe above worked
unchanged, including every NULLTAG, so this is an addition rather than a correction.
The note above says to match "on displayName substring, or compare on the
underlying uid". On this tier the second option does not exist. A
getOccurrences4 child row is exactly this and nothing more:
{"occurrenceId": "SR::N::Arm0RequirementElement..Fnd0RequirementBOMLine..9....",
"stableId": "<specRevUid>:<occUid>",
"displayName": "1 CS-01 Crane hook attachment, single lifting eye on centreline",
"numberOfChildren": 0,
"underlyingObjectType": "Requirement Revision",
"position": 32,
"occurrence": {"uid": "AAAAAAAAAAAAAA", "className": "unknownClass", ...}}
occurrence.uid is NULLTAG, and there is no underlyingObjectUid member at all.
stableId is specRev:occurrence, not specRev:requirementRevision, so it does not
give you the object either.
⚠ The failure this produces looks like data loss, not like an instrument fault. A
verifier that harvests uids from these rows collects one value, AAAAAAAAAAAAAA, and
then reports present=0 missing=32 for a structure that is completely correct. That
happened here on the first verification run, immediately after 32 successful adds, and
the two numbers sitting side by side in the same output (children=32 and
missing=32) are what exposed it. Had the run placed nothing, the same code would have
printed the same missing=32, so that verifier could not distinguish total success
from total failure.
⇒ Two rules fall out:
- Match on
displayNamesubstring, and treat the uid path as unavailable unless you have confirmed on your tier that a uid is actually populated. Remember the number prefix:"1 CS-01 ...", solabel in name, nevername == label. - Cross-check identity through the BOM-window path, which uses a different id
space and does carry real ids.
bl_item_item_idon the child occurrence lines returnedREQ-002825 .. REQ-002856, 32 distinct, 0 missing, 0 unexpected. That is the check that proves the things in the spec are your objects rather than 32 of something else, whichdisplayNamematching alone only makes likely.
★ Run the verifier before the writes as well. A baseline run here reported 0 by both instruments, which proved the instruments could return a number at all and made the after-state attributable to the writes. A verifier that has only ever been run against the expected answer has not been tested.
Related
tc-capture-awc-calls (how both calls were obtained), tc-traceability-matrix (what
the occurrences are for), tc-object-authoring, tc-verify-and-cleanup,
tc-bom-structure (the removal call and BOM-window cross-check both come from
here), diagnose-silent-failure.
Generated from skills/tc-requirement-spec-content/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.