Skills
Cameo TC Element Authoring
Skill
cameo-tc-element-authoring. Author SysML in Cameo so it actually lands in Teamcenter through the HCL connector. Covers the element-type landing matrix (what each Cameo type becomes in TC), the three gates that decide whether something exports at all (a port needs a part-property occurrence, a connector needs factory ends plus propertyPath, an object flow needs CallBehaviorAction endpoints), the direction rules that make Allocate and Verify work or silently fail, the "set only at creation" class of traps where editing an existing element is ignored with no error, the two relations that never export despite 330 declared rules each, and the verification discipline (server-side reads only, because the headless Check-In never stamps TC ids back into the model). Use for any Cameo model that must reach Teamcenter, any "the export succeeded but nothing is there" investigation, and before writing modeling guidance for other people.
EXERCISED 2026-08-17 on vm2606 (https://siemensdc/tc, TC 2606, user ed) across 21
incremental Check-Ins of model CSA_ProbeManual (item 007106), driving the HCL Cameo Connector
headlessly. Every row below was verified by a server-side SOA read, never by the connector's
return value. Mapping reference: MAGICDRAW_BHMIntegrationDefinition_TC2506.xml.
Companion detail, with the failed attempts kept:
Capital_TC_Integration/docs/CAMEO_ELEMENT_LANDING_MATRIX.md and
Capital_TC_Integration/docs/CAMEO_CONNECTOR_DEFECTS.md.
The landing matrix
| Cameo | Teamcenter | notes |
|---|---|---|
| Block | Fnd0LogicalBlock |
seg0Kind = the applied stereotype name |
| Part property (composite, «PartProperty») | Fnd0LogicalBOMLine child |
this is the decomposition |
| ProxyPort typed by an interface block | Fnd0LogicIntrfce |
only via a part occurrence, see Gate 1 |
| Connector | Fnd0LogicConn |
endpoints on the OCCURRENCE, see Gate 2 |
| Interface Block | Seg0Interface |
|
| Signal (bare UML metaclass) | Seg0IntfSpec |
no stereotype needed |
| Flow property on an interface block | Seg0ItemFlow |
via Seg0ExchangeAllocation |
| Item Flow («ItemFlow» InformationFlow) | Seg0ItemFlowExchanges |
via Seg0Implements |
| Activity | Functionality |
no stereotype needed |
| Activity Parameter Node | Network_Port |
GDELine occurrence under the Functionality |
| Object Flow | Network |
only from CBA pins, see Gate 3 |
| Value property + «TC_Parameter_Stereotype» | Att0MeasurableAttribute* |
value rides a tagged value |
| Requirement | Requirement |
subtypes are extends, they behave the same |
| Package | Uml0Package |
contents become BOM children |
| Diagram | Seg0Diagram |
attached via Fnd0Diagram_Attaches |
| Project | Uml0MLModel |
|
| mdzip | Mdw0MDModel |
|
| Action / OpaqueAction | nothing | the mapping declares no Action rule at all |
Gate 1: a port needs a part-property occurrence
A ProxyPort on a block produces no TC object until something owns that block through a part
property. This is the GBVR (grandchild) behaviour in the mapping.
Symptom: ports exist in the model, carry no TC id, and are absent from Teamcenter, while the blocks around them landed fine.
Fix: give the ports' blocks a parent block with composite part properties. The ports then appear with no edit to the ports themselves:
ProbeSystem
Fnd0LogicalBOMLine -> Alpha rev
GDELine -> Fnd0LogicIntrfce <- the port, now real
Use ProxyPort. Bare Port and Full Port are declared in the mapping but are bad practice
on this stack and have caused trouble before. ⚠ Measured 2026-08-28 (ZZCOV probe, vm2606): all
three port kinds DO export as Fnd0LogicIntrfce, discriminated by seg0Kind (empty /
FullPort / ProxyPort), so the convention is about downstream consumers keying on ProxyPort,
not about the export failing.
Gate 2: connector ends come from the factory, and need propertyPath
conn = f.createConnectorInstance() # ALREADY supplies exactly 2 ends
conn.setName("AlphaToBeta")
conn.setOwner(owningBlock)
ends = list(conn.getEnd()) # do NOT add your own
def wire(en, port, part):
en.setRole(port)
en.setPartWithPort(part)
StereotypesHelper.addStereotype(en, nce) # NestedConnectorEnd
StereotypesHelper.setStereotypePropertyValue(en, nce, "propertyPath", [part])
wire(ends[0], portA, partA)
wire(ends[1], portB, partB)
⚠ Adding your own ends produces a 4-end connector that silently fails to serialise.
saveProject returns true and the connector is then simply absent from the .mdzip. This is a
strong suspect for any unexplained Export Failed: The given value is invalid.
Endpoints live on the connector's occurrence, never on the item:
getProperties(<connector BOMLine>, ["fnd0bl_connected_end1", "fnd0bl_connected_end2"])
Gate 3: an object flow needs CallBehaviorAction endpoints
An ObjectFlow exports only when its source and target pins sit on a CallBehaviorAction
whose behavior is an Activity that itself exports.
Measured, four shapes:
| shape | result |
|---|---|
| ActivityParameterNode to ActivityParameterNode | does not land |
pins on plain OpaqueActions |
does not land |
| ActivityParameterNode pair drawn on a real SysML Activity Diagram | does not land |
pins on CallBehaviorActions with an exported behavior |
necessary, NOT sufficient - see Gate 3b |
The diagram theory is refuted, not untested: the flow was placed on an activity diagram that the
connector's own filter accepted (its diagram count rose) and no Network appeared. The name is
irrelevant; a flow named from birth lands fine.
Gate 3b: BOTH end nodes need a non-null getSyncElement()
★ This is the gate that Gate 3 above misses, and it is the one that fails silently. Gate 3 is
necessary and NOT sufficient: pins can sit on perfectly good CallBehaviorActions whose behaviors
export, and the flow still produces no Network, with no fault and no error in the publish result.
EXERCISED 2026-08-26 on vm2606, read off the shipped jar and then proven by fixing it.
From CameoTCIntPlugin.jar, com.hcl.cameotc.integration.service.relationMgmt.CameoElementsRelations .prepareForObjectFlow (decompiled with the JRE's own javap):
ActivityNode src = flow.getSource();
ActivityNode tgt = flow.getTarget();
if (src == null || tgt == null) { valid = false; return valid; }
Element s = src.getSyncElement();
Element t = tgt.getSyncElement();
if (t == null || s == null) { valid = false; return valid; } // <-- THE GATE
The exclusion reason recorded is the literal resource key Validation_for_ObjFlow. Its message in
Resources_en_US.properties is:
Object Flow should have Input and Output Pin at ends.
⚠ That message is MISLEADING and cost this workspace days. The failing flows all had a correct
uml:OutputPin at source and uml:InputPin at target. The rule does not test the metaclass of the
ends at all; it tests whether each end node carries a syncElement.
What syncElement is. Element.getSyncElement() / setSyncElement(Element) are public on
com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Element. On a pin it is the link to the
Parameter on the called behavior that the pin mirrors. MagicDraw sets it when IT generates the
pins by synchronising a CallBehaviorAction against its behavior's parameters. A pin created
programmatically with EF.createInputPinInstance() / createOutputPinInstance() and merely added
to the action has syncElement == null, so every object flow authored from Jython fails this
gate unless you set it yourself.
The fix, and it needs no re-authoring:
# for each end node of the flow
beh = pin.getOwner().getBehavior() # the called Activity
param = next(p for p in beh.getOwnedParameter() if p.getName() == pin.getName())
pin.setSyncElement(param) # <-- this is the whole fix
Create the matching Parameter (plus its ActivityParameterNode) first if the behavior does not
have one. Then save, deep sync, Publish.
Measured result. In 007916 Confirm and Geolocate, 19 of 20 pins had a null syncElement,
including the six flows that had ALREADY crossed - so all nine flows in that file were being
excluded on every publish. The six only looked healthy because they already carried TC uids from an
earlier pass and did not need re-creating. After setting syncElement on all 20 pins and one
Publish, the tier's Network count went 55 to 59. The same fix on 007913 Fly and Navigate took it
59 to 65. Ten nets that had never existed, recovered without re-authoring a single flow.
⚠ A published model can LOSE this. Those six had crossed originally, yet their pins read null
afterwards. Publish rewrites the local file from Teamcenter, and syncElement does not survive the
round trip. So re-check it before every publish, not once.
⚠ syncElement is NOT serialised in the .mdzip under any name the offline auditor can see, so
this cannot be checked with mdzip_audit.py or any XMI parse. It takes a live Cameo and one call
per pin. Do not conclude from a clean offline audit that the flows will export.
The one shape this does not rescue
A flow whose end is an ActivityParameterNode owned by the parent Activity (a delegation of a
sub-function's output to the parent's own output parameter) is not a function-to-function link.
Binding its syncElement to its Parameter makes it pass the gate, and the publish then fails
anyway. Treat delegation flows as out of scope for Network until someone proves otherwise.
Gate 3c: the endpoint functions must be PACKAGE members, not nested Activities
★ EXERCISED 2026-08-26 on vm2606, by controlled experiment. An ObjectFlow whose endpoint
behaviors are Activities owned by another Activity produces no Network. Move the same
Activities so a Package owns them, change nothing else, and the flows export.
This is a THIRD independent condition. Gate 3 (pins on CallBehaviorActions), Gate 3b
(syncElement on both end nodes) and Gate 3c all have to hold. Each one fails silently and the
publish still returns ok: true.
How it was isolated, because the result is only worth what the method is. The JPO MSP-2
reference architecture had 8 functions nested inside a parent Activity MSP2-FN-ROOT, wired with
13 object flows. Everything else was already right and verified server-side: all 23 Parameters
crossed as Network_Port, all 9 functions as Functionality, both new Signals as Seg0IntfSpec,
all 13 flows passed Gate 3 and Gate 3b. Zero Networks, across THREE publishes.
Eliminated first, each by measurement rather than argument:
| candidate | how it was killed |
|---|---|
syncElement null |
set on all 26 end nodes and re-read; still zero |
| same-publish ordering (Parameters had no TC uid yet) | 2nd publish, no model change; still zero |
| endpoint functions not allocated | 8 Seg0Allocate created and READ BACK off 007239/A;1 in Teamcenter; still zero |
| flow-owning parent not allocated | 9th Seg0Allocate added; still zero |
| endpoints performed by the SAME block | falsified from the wildfire control: GeodeticFix, TerrainModel and ProbeQualityMetric all have producer and consumer on one block (Geolocation Solver) and all three ARE Networks |
Then the minimal test. Two functions either side of ONE flow (MSP2-FN-3 -> MSP2-FN-1,
carrying SIG-TIMING-REF) were re-homed from the Activity into the package. One publish:
Network nFound 65 -> 66 the single new item is 007987-SIG-TIMING-REF
Exactly the one flow whose BOTH endpoints moved. The other 12, still nested, did not appear. Moving
the remaining 6 functions and publishing again took it 66 -> 78, all 13 verified individually by
uid as object_type = Network.
The rule: a function that must carry object flows has to be owned by a Package. Use
composition or an allocation relation to express the decomposition, not Activity nesting. Element
ids are stable across the re-home, so existing Teamcenter items are preserved: the 8 MSP-2
functions kept items 007256-007265.
⚠ Nesting is legal SysML and looks tidier in the containment tree, which is why this is worth
writing down. Nothing in Cameo, in the deep-sync report, or in the publish result objects to it.
The only symptom is a Network that never appears.
Direction decides Allocate and Verify
The mapping is fully cross-product and permits far more than the connector delivers. Direction, not declaration, is what works.
| relation | working direction | wrong direction |
|---|---|---|
| Allocate | client = Block, supplier = Activity (structure to behavior) | Activity to Block aborts the entire Check-In |
| Verify | Requirement to Requirement | Activity to Requirement produces nothing |
| Derive | Requirement to Requirement, either way | |
| Satisfy | client = Block, supplier = Requirement |
⚠ The wrong-direction Allocate fails with a message that misdescribes the cause:
Relating an object of type "System Block Revision" to an object of type "Function Revision"
is not allowed, because the "Allocate" relation is not supported between these two objects.
That pair IS permitted: createRelations with exactly those revision types succeeds, and the
working direction produces that same pair. Worse, the failure then blocks every subsequent
Check-In of that model, not just its own element. If check-ins start failing after an
allocation edit, delete the Allocate first and re-push before debugging anything else.
Set only at creation
A whole class of traps: the element exports correctly when created right, and editing it afterwards is silently ignored.
- Item flow source/target. Set
informationSource/informationTargetto Blocks when you create the InformationFlow. Editing them later leavesseg0Source/seg0Targetempty forever. Delete and recreate instead. Measured on both sides, see the section below. - Connector ends. As above.
- Object flow endpoints. As above.
- Package contents. Create the element inside the package. Do not move an existing one in.
This is not a blanket "edits never propagate": renaming propagates, and re-pointing a Verify abstraction propagates. It bites structural and REF-behaviour links.
⇒ When something structural does not appear, delete the element and author it correctly from scratch before concluding the capability is missing. That single move settled two "defects" that were not defects.
Item flows: the ends, and how to read them back
EXERCISED 2026-08-24 on vm2606, both halves, across two models and 130 objects. This is the one
rule in this file with a controlled comparison behind it rather than a single observation.
In Cameo, the ends are CHILD ELEMENTS carrying xmi:idref, not attributes. A regex looking for
informationSource='...' on the opening tag finds nothing and reads as "no ends set":
<packagedElement xmi:type='uml:InformationFlow' xmi:id='...' name='Fuel From Main Tank'>
<conveyed xmi:idref='...'/> <!-- uml:Signal -->
<informationSource xmi:idref='...'/> <!-- uml:Class, the BLOCK, not the port -->
<informationTarget xmi:idref='...'/> <!-- uml:Class, the BLOCK, not the port -->
<realizingConnector xmi:idref='...'/>
</packagedElement>
The measured contrast, which is what makes the Blocks rule a fact rather than a preference:
| model | what the ends point at | seg0Source |
seg0Target |
Seg0HasExchangeItem |
|---|---|---|---|---|
IFFS_Exercise (007146) |
uml:Class |
9 / 9 | 9 / 9 | 9 / 9 |
| SENTINEL-W, before re-author | uml:Port |
0 / 121 | 0 / 121 | 121 / 121 |
⇒ Port ends do not fail to publish. They publish a Seg0ItemFlowExchanges object that conveys its
Signal correctly and does not say what it connects. That is a narrower and more dangerous defect
than "it did not land": the object count is right, the conveyed item is right, and only the
endpoints are missing, so anything checking presence rather than content scores it as a success.
Reading one back, and the casing trap
The properties are on the Seg0ItemFlowExchanges object itself. Plain getProperties, no GRM
traversal. ⚠ The type mixes naming conventions, and a wrong-case name returns EMPTY exactly like a
genuine absence:
| property | case | holds |
|---|---|---|
seg0Source |
lower | the source Block, e.g. 007123-FuelPressureSensor |
seg0Target |
lower | the target Block, e.g. 007119-FuelControlUnit |
Seg0HasExchangeItem |
CAPITAL S | the conveyed Signal, e.g. 007199-FuelPressureSignal |
object_string |
derived <source>-<target> |
Asking for seg0HasExchangeItem returns nothing on a healthy object, which is how one
investigation concluded the conveyed Signal had not crossed when all 121 of them carried it. Same
family as the malformed-preference-probe trap: a bad name and a real absence are the same result.
⚠⚠ Active Workspace's "External Connections" table is NOT the flow direction, and it disagrees
with seg0Source/seg0Target BY DESIGN. EXERCISED 2026-08-28 on connector 007204
(IFFS_Exercise), prompted by Chris's manual AWC check after "the seg0 check regularly gives
incorrect results": the Interfaces page's External Connections table showed Source System =
007119-FuelControlUnit / Source Port = dataIn / Target System = 007123-FuelPressureSensor,
the exact REVERSE of the exchange's seg0Source/seg0Target. Reading the connector OCCURRENCE
settled it: that table renders the connector's ENDS under "Source"/"Target" column headers
(fnd0bl_connected_end1 = dataIn.1 on FuelControlUnit, end2 = dataOut.1 on FuelPressureSensor).
End order is creation order and carries no flow semantics: an INPUT port sitting in the "Source
Port" column is the giveaway. The flow direction lives on the Seg0ItemFlowExchanges object,
which the SAME page's Exchange Items grid shows correctly, so one AWC page can display both
vocabularies disagreeing. Anyone comparing the External Connections columns against
seg0Source/seg0Target will see them "wrong" roughly half the time. Two different property
pairs share one column name; neither is broken.
Reachable from the connector as Fnd0LogicConnRevision -> Seg0Implements -> the
Seg0ItemFlowExchanges, which is how the forward transform collects carriers.
★ The one-property acceptance check
object_string is DERIVED from source and target. Populated on all 9 good ones
(007123-FuelPressureSensor-007119-FuelControlUnit), empty on all 121 bad ones.
⇒ After a publish, read object_string on the item-flow objects. Non-empty means both endpoints
landed; empty means they did not. One property, one glance, and a partial write cannot fake it.
⚠ THIS CHECK IS SPECIFIC TO Seg0ItemFlowExchanges AND MUST NOT BE GENERALISED. object_string
is DERIVED from source and target only on that type. Everywhere else it is the ordinary
id-plus-name display string, which is non-empty on every healthy object and says nothing whatsoever
about wiring:
| type | object_string |
usable as a wiring check |
|---|---|---|
Seg0ItemFlowExchanges |
007123-FuelPressureSensor-007119-FuelControlUnit |
yes, it is derived |
Network |
007919-ThermalAnomaly |
no, id + name |
NetworkRevision |
007919/A;1-ThermalAnomaly |
no, id + rev + name |
Applying it to a Network would report every net as correctly wired, always. Caught by the Wildfire
session on 2026-08-24 immediately after this entry was first written without the caveat.
⚠ It also does NOT cover the conveyed item: the 121 broken flows have Seg0HasExchangeItem
populated and object_string empty. Check both if you care about both.
The functional layer: Networks are ITEMS, and carry no endpoints
EXERCISED 2026-08-24 on vm2606, and this is the counterpart to the item-flow rule above: the two
layers store their connectivity in completely different places.
An object flow between CallBehaviorAction pins lands as a Network (item) / NetworkRevision,
whose item-level type is PSConnectionRevision. It carries no endpoints. Four routes tried, all
negative, each with the instrument proven working on other objects in the same session:
| route | result |
|---|---|
seg0Source / seg0Target on the NetworkRevision, any casing |
absent from the type, not merely empty |
expandGRMRelationsForPrimary / ForSecondary from the NetworkRevision |
only NetworkRevision Master |
| connection occurrences in the owning model's BOM | the 4 found are BLOCK connectors, no Networks |
| connection occurrences in the Functionality's own BOM | its pins are there, 0 connections |
⇒ Do not go looking for the wiring on the Network. It is a named net, nothing more.
★ The connectivity IS recoverable, by joining function pins on their SIGNAL. A Network_Port
occurrence under a Functionality carries a durable signalUids (plus a readable signalRefs), so
two pins on two different Functionalities that share a signal uid are the two ends of that net.
Measured on 007912 (Detect Ignition): 88 Logical Port occurrences, 39 carrying a signal uid, 11
distinct signals, 11 of 11 spanning two or more different parent functions, 0 orphans - and the
reconstructed net names match the Network item names one for one.
⇒ Join on the uid, never the name. The names coincide here (VnirFrame the pin, VnirFrame the
Network, 007854-VnirFrame the signal) which makes name-matching look sufficient, and signal names
are documented elsewhere in this workspace as NOT unique across items.
Parameters: structure and value have different carriers
Setting a SysML default value creates the parameter and an Att0MeasureValue* with a real
att0DateMeasured and an empty value. That reads like partial success and is not.
The value carrier is the stereotype tagged value:
TC_Parameter_Stereotype.Measurement -> att1Value direction Both
Set Measurement and both att1Value and the MeasureValue's att0Value populate.
Still broken and not fixable from Cameo: att0AttrDefRev self-binds to a datatype-shaped
default definition (e.g. Double (each)) with att0Uom empty. ObjectId is mapped TcToTool
only, so the real definition must be bound Teamcenter-side. See tc-parameters-units.
Relations: what works and what does not
Confirmed working: Seg0Satisfy, Seg0Derive, IAV0Verify (req to req only), Seg0Allocate
(structure to behavior), Att0HasParamValue, Seg0Implements, Seg0HasExchangeItem,
Seg0ExchangeAllocation, Fnd0Diagram_Attaches, Item Flow::seg0Source / seg0Target,
Flow Property::seg0ExchangeItem.
Confirmed NOT working: Seg0Refine and FND_TraceLink. 330 declared rules each. Four
configurations apiece (both directions, shared pair, and a brand-new pair carrying no other
relation), with three controls: a positive instrument control in every call, a fresh-element
control, and a cardinality control. They simply do not come across.
⇒ For refine and trace links, author TC-side with createRelations. That works, and the relation
survives a later Cameo Check-In (proven with Allocate) because the connector does not clobber
relations it did not create.
✅ Seg0Specializes (Generalization): EXERCISED 2026-08-28 on vm2606 (ZZCOV probe). A block-to-
block Generalization crosses as a Seg0Specializes GRM relation, child REVISION -> parent ITEM.
No reference property is compiled on either revision (both casings return dropped-name), so read
it with expandGRMRelationsForPrimary (relationName filter member, expItemRev required) and
carry a known-good relation in the same call as the instrument control.
Also from the same probe: a flow property typed by an in-model «ValueType» DataType allocates and
resolves seg0ExchangeItem exactly like a Signal-typed one, while a BARE uml:DataType flow
property allocates nothing even though the DataType itself lands as a Seg0IntfSpec. The
signal-typing rule is about in-model-ness plus stereotype family, not metaclass.
Jython authoring traps
- An
InformationFlowcannot be owned by a Class.setOwner(block)throwsIllegalArgumentException: can not find container for. Own it in a Package. ActivityusesgetNode(), notgetOwnedNode().- Own a Satisfy or Allocate
Abstractionafter thegetClient()/getSupplier()writes: those writes re-home it. - The
Requirementstereotype's ownownedAttributeis only[base_Class].IdandTextare inherited fromAbstractRequirement;setStereotypePropertyValuestill finds them. - Keep Jython pure ASCII.
- Wrap every model modification in a named session so a failure rolls back cleanly.
- For a stereotype sourced from a used project, do not call
setStereotypePropertyValuein the same session as theaddStereotype: the entire stereotype application is silently discarded. Apply the stereotype in one session, set the tagged values in a second. This can turn a stamped «TC_Parameter_Stereotype» back into an unstamped one, which aborts the next push. (Relayed 2026-08-28 from the "Library palettes for functions and performers" session, root-caused and exercised there; not re-run here.)
The working order, and why each step is where it is
Check-Out -> author -> save -> mark for Deep Sync -> Check-In -> verify server-side
Both of the middle steps were learned by getting them wrong on a live model in one sitting.
Author AFTER the Check-Out, never before. A Check-Out pulls from Teamcenter and discards local edits. Eleven allocations and nine parameter values authored before a Check-Out were silently gone afterwards: the file shrank, the counts read zero, no warning of any kind. This is the same family as the long-standing "Synchronize pulls, it does not push" trap.
⚠ Correction: an earlier version of this note also named Put Model as a pull. It is not. There are three distinct pushes/pulls, and conflating them costs a duplicate item or a discarded edit: Put Model sends a NEW model and always mints a new TC item (the correct mode for a model that does not yet exist, the wrong one for a model that does, where it silently creates a duplicate); Publish updates an EXISTING checked-out model in place; Synchronize is the one that pulls. Both Put Model and Publish can optionally preserve the checkout. See "Re-publishing a model as NEW" below for the Put Model path in full.
Mark for Deep Sync AFTER the save and BEFORE the Check-In. A Check-In with nothing marked reports success and lands EMPTY containers, which in an update overwrites what was already there. Measured: a model reading 182 occurrences in Teamcenter dropped to 1 after a clean, error-free Check-In. Marking all 5,334 elements and re-pushing restored it to 185. Nothing warned, and the run that destroyed the content looked exactly like the run that restored it.
⇒ A clean Check-In is not evidence. Re-read the occurrence count server-side after every push.
Re-publishing a model as NEW (stripping Teamcenter identity)
When a model's Check-In is broken and you want a clean item rather than a repair, strip its TC identity and use Put Model, which is a different code path from the Check-In/update path:
- Unmark Deep Sync on everything (
CameoUtil.stopSharing(id), walked recursively). - Remove the Teamcenter identity. Removing the Teamcenter profile is the intended route, but
it is an attached read-only module:
ModelElementsManager.removeElementraisesReadOnlyElementException, andModulesService.detachModulesOnTaskwants aModuleUsage, not theIAttachedProjectthatProjectUtilities.getAllAttachedProjectsreturns. The route that worked was removing the stereotype APPLICATIONS instead (StereotypesHelper.removeStereotypeforTC_Object_Stereotype,Teamcenter_Data,TC_CheckIn_CheckOut_Stereotype,TC_Share_Unshare_Stereotype,TC_Parameter_Stereotype). Skip read-only elements: those live in the UML/SysML/ISO profiles and carry no model identity. - Save.
- Mark for Deep Sync.
- Put Model.
⚠ This costs you the parameter stamps. TC_Parameter_Stereotype goes with the strip, so
parameters do not export at all on the fresh push and must be re-applied afterwards. Measured:
parameters: 0 on the first read of the new model.
Note com.nomagic.magicdraw.core.ProjectUtilities is the class that resolves;
com.nomagic.magicdraw.core.project.ProjectUtilities does not exist.
After a Put Model the project is not checked out, so the next push needs a Check-Out.
⚠ Correction, 2026-08-28: this note previously said headless Check-Out remains blocked. It is
not. cameo_ops_checkout (route="import", CameoProgressBarServiceImpl.importProject(...) with
flags[0]=true) was EXERCISED 2026-08-20 and re-verified 2026-08-24 on vm2606 (ZZP00_Containers /
000518), with the server-side checked_out flip read over an independent SOA session and an
untouched-item control. ⚠ The vendor's own checkout() on its own STAGES A FILE AND RESERVES
NOTHING while returning a plausible response with a staging path; that call is the trap this
correction replaces. (Source: the cameo-mcp session and the "Another Headless Cameo" session;
operational detail in RECIPES.md and cameo-mcp/docs/STATUS.md.)
Verifying: server-side only
⚠ The headless Check-In path does not write TC ids back into the model. The GUI path does.
Measured in one read on one model: three GUI-created elements carried
Teamcenter_Data.itemid + stableTcId, and eight headless-created elements carried nothing
while all eleven existed in Teamcenter.
⇒ Walking the model for stamps to decide what landed under-reports. It is not a valid test.
Identity is still maintained server-side (keyed on cifContainerIdentifier, the Cameo element
id), so re-pushing updates in place rather than duplicating. Across 21 pushes nothing forked.
Other verification notes:
exportRequirementsreturns a JsonObject describing what it intended to send, on paths that create nothing. It is not evidence.- The Check-In path writes no payload to the connector log.
Input JSON of Exportis the Put Model / export path only. Do not read its absence as proof of anything. Seg0ItemFlowExchangeshas an emptyobject_string, sotc_query_by_typereports 0 for it however many exist. DereferenceSeg0Implementsfrom the connector instead.- A flow property's result is a GRM relation on the interface revision
(
Seg0ExchangeAllocation), not BOM structure. A BOM expand finds nothing and reads as failure. - For relations whose GRM primary is
WorkspaceObject(Derive, Refine), no reference property is compiled on either endpoint. UseexpandGRMRelationsForPrimarywith an explicitrelationNamefilter, and always include a known-good relation in the same call as a positive control. - ★ The connector stamps the PARAMETER, not the
ActivityParameterNode. The landing matrix line "ActivityParameterNode -> Network_Port" is true about the MAPPING and false about which element carries the Teamcenter identity.processActivityParameterNodefetches the node, then callssetID(parameter.getID()), so the TC object is keyed on the Parameter. EXERCISED 2026-08-26 on vm2606: a stereotype scan of the 23 ActivityParameterNodes on the MSP-2 functions returned 0 crossed while the 23 Parameters returned 23 of 23, and the Network_Ports existed the whole time. ⇒ Verify the Parameter. Scanning the node reads as a total failure of the port layer. - ★ Allocate relations carry NO
tcuidand NOTC_Object_Stereotype. They become GRM relations, not items, so they never receive the stereotypes an item gets. Their absence from a stereotype scan is not evidence they failed: 0 of 16 in one file, 15 of which were confirmed present on the tier. ⇒ ReadSeg0Allocateoff the BLOCK REVISION (not the item, not the Activity), and put a deliberately fake property name in the same call as a control, becausetc_get_propertiessilently drops unresolvable attribute names and an absent property is otherwise indistinguishable from an empty one. EXERCISED 2026-08-26: readingSeg0Allocateon007239/A;1-MSP2-LB-ROOTreturned all 9 function revisions, withfnd0ThisIsAFakeControlPropertydropped from the same response, proving the read discriminates.
A minimal model that exercises everything
Package Sensors
Block System parts: a : Alpha (composite), b : Beta (composite)
value property rate : Real + «TC_Parameter_Stereotype» Measurement
Block Alpha ProxyPort out : Link
Block Beta ProxyPort in : ~Link
InterfaceBlock Link flow property sig : DataSignal («FlowProperty», direction out)
Signal DataSignal
Connector on System out@a <-> in@b, both ends «NestedConnectorEnd» with propertyPath
ItemFlow conveyed DataSignal, realizing the connector,
source = Alpha, target = Beta (BLOCKS, at creation)
Activity Acquire ActivityParameterNodes typed by DataSignal
CallBehaviorAction -> Activity Sample (with pins)
CallBehaviorAction -> Activity Publish (with pins)
ObjectFlow between the CBA pins
Requirement R1, R2 Derive R2->R1, Verify R2->R1
Satisfy System -> R1
Allocate Alpha -> Sample (structure to behavior)
Related skills
cameo-connector-config (environments and release switching), cameo-headless-automation
(driving Cameo through the bridge), tc-parameters-units, tc-relations-traceability,
tc-query-discovery, diagnose-silent-failure.
Task-ordered cookbook over these mechanics, with the test-model roster and the peer-session
findings ledger: RECIPES.md in this skill folder.
Generated from skills/cameo-tc-element-authoring/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.