TeamcenterKnowledge

Skills

TC Verify And Cleanup

Skill tc-verify-and-cleanup. The grounding discipline for Teamcenter automation: never report an object a tool call did not return, re-verify every create, find test litter by name rather than by a uid ledger, and the retry pattern for "the instance is referenced" delete failures. Use at the end of any TC authoring session, and any time you are about to state a TC item id or status.

The grounding rules (non-negotiable)

  • Every object you claim to have created or modified must be re-verified by a live getProperties on the uid the create call returned, before you report it.
  • Harvest uids from tool RESULTS only.
  • Never state a TC item id, uid, dataset name, or workflow status that a tool call did not return.
  • If the tools are unavailable, or a step (a release workflow, a status transition) is not SOA-executable on this instance, say so plainly and mark the criterion unmet. Blocked and honest beats complete and fabricated.
  • Requirement text, parameter values, and any other content belong on the TC object (a named property or a Text dataset), never only in your prose. If a future session cannot pull it back out of TC, it was not authored, it was claimed.

These exist because of a real incident: an agent with no tools fabricated a complete "TC Check-In Record" including an invented item id and a "Released / Baselined" status. That failure mode is watched for.

The positive counterpart is equally real: a run against a new instance where generic createItems faulted reproducibly, nothing was created, and the run reported "not authored, not verified, blocked" rather than inventing a uid. That is the standard.

Never say "verified" without a relation to point at

A requirement's status is a property on a TC object, not a sentence you write. "Satisfied", "verified", "closed", "traced", "covered" each require a real relation object or property value backing them. If the transition is not SOA-executable, the requirement is authored-but-unverified, and that is what you report.

Watch for the reference-property blind spot: relations whose GRM primary type is the generic WorkspaceObject (Seg0Satisfy, Seg0Derive) create successfully but read back as nothing. Do not ship a check that silently fails on genuinely correct work; mark it unverifiable and say why. See tc-relations-traceability.

Hold your own verifier to the same standard

A live re-verify pass once flagged two relations as missing that had just been created successfully. The relations were fine. Two separate bugs were found by taking the red result seriously:

  1. The relations were WorkspaceObject-primary and genuinely unreadable via the reference-property shortcut, so the contract set them to min: 0.
  2. They were still reported missing, because the verifier's own relation loop had const min = Math.max(1, req.min ?? 1), a floor that silently overrode an explicit min: 0.

"Prove it, do not assume it" applies to your verification code too.

The control must match the VERDICT ARITY of what it controls

Adopted 2026-08-13. A model-audit suite reported 26 of 26 green. Asked what that would look like if it were not true, the author went to quote their negative control, and the control did not exist: the audit's header had claimed since its first version that every check runs against a deliberately broken fixture, naming a file nobody had ever written. A rule without an emitter, living in the one file whose whole job is catching that shape, surviving four clean grades because a header is not something a reader thinks to check.

A claim that a control exists is not a control, and it is the highest-value place for that failure to hide, because attention is on the results.

Building it properly produced the sharper finding. Nine of ten checks fired against injected faults; the tenth did not, and the check was right while the CONTROL was wrong. That check signals CANNOT_TELL, never FAIL, because missing data is not a failure. The control inspected only the FAIL bucket, on a suite deliberately built three-valued. A correct three-way check looked dead to a two-valued instrument.

A wrong control does not merely miss defects, it manufactures them. Trusting that run would have led to "fixing" the check by making it FAIL on missing data, breaking the three-valued contract to satisfy a broken instrument.

⇒ Assert "did the verdict change, and to what", never "did anything fail". That is strictly stronger anyway: it also catches a check that stays PASS while degrading.

And pair it with the opposite sign, from the same day: a contract written as data survived a wording error in its own prose, because the code asked for a structural property while the document said the wrong metaclass name. There the checker was right and the prose was wrong; here the checker was right and the meta-checker was wrong. Whichever layer you trust least is the one to write as data and exercise against known-bad input.

On a shared tier, mark what you AUTHOR or someone will measure it as native

Adopted 2026-08-12, after it happened. A session hand-authored 12 Seg0Implements relations to repair a port-to-interface gap, correctly, verified each by read-back, and recorded every uid. A second session then read those relations off the tier, concluded that the Cameo-to-Teamcenter connector populates Seg0Implements, and retracted a correct standing claim in a shared context file on the strength of them. Their quoted evidence was one of the authored pairs, and their count of "11 already linked" equalled the first batch exactly.

Nothing about the write was wrong. The absence of a provenance marker was.

⚠ A hand-authored relation and a connector-authored relation are byte-identical on read. This is the same shape as the cap and scope traps elsewhere in this skill set: the true and the false case produce the same response, so no amount of care on the READING side catches it. Only the writer can prevent it.

The trap has a nasty second-order form: authored data usually makes the tier look better, so it lands as a satisfying positive result. The other session did not find a discrepancy to chase, they found confirmation, which is the version nobody double-checks.

⇒ Before writing anything to a tier another session reads:

  • Say so, in the channel that session actually reads, before or immediately after the write, not only in your own repo.
  • Record the uids where they will look, not just where you will look. A measured-facts file in your own repo is not where someone auditing the tier goes.
  • Prefer a marker the reader can see over a bare correct write: a naming convention, a note or description field, a dedicated relation, a distinguishable revision. If the write must be indistinguishable, treat announcing it as part of the write rather than as courtesy.
  • Ask whether authoring is even yours to do. Repairing another team's model on a shared tier changes what their measurements mean. Offer it; do not assume it.

The misattribution has a second form, walked into while reporting the first. Content sitting in a shared context file is not content authored by the person you are talking to. A BOM comparison read out of a repo CLAUDE.md was credited to a correspondent who had never run it, and they had to refuse a stronger claim than their own evidence supported. "It was in the context I was given" is the same reasoning that turns authored data into someone else's measurement. Attribute by checking who wrote it, not by which document it arrived in.

The corollary for READING a shared tier: a count you took is a snapshot, not a tier fact. On the same tier the same day, Seg0Interface went 20 to 40 and Fnd0LogicIntrfce went 62 to 160 inside one session while another was authoring. Neither reader was wrong and neither query was defective. A difference between two counts taken by two sessions on a live shared tier is not a finding until both are re-read in the same window, and any count you publish should carry the time it was taken.

Reverting a write: assert on what you REMOVED

An empty property is the expected result of a correct undo and the symptom of deleting the wrong thing. The end state cannot tell them apart, so checking it proves nothing.

deleteRelations returns a deleted array. Compare it against the set you authored and confirm nothing outside that set appears, then re-read the objects as a second, independent check. Reverting 12 hand-authored Seg0Implements relations this way returned exactly those 12 uids; had it returned 37, the ports would have read empty either way.

The same trap sits behind git rm --cached, git checkout --, git reset, and any DELETE with a stale WHERE. An undo is a diff, so verify the diff.

Cleaning up test objects

Do not rely on a session-long uid ledger. It drifts: untracked first-pass creates, relation uids never captured. Freestanding creates (no container) never land in a Newstuff folder listing and cannot be enumerated by folder walk.

Search by NAME instead, using the OOTB saved queries:

Query-2006-03-SavedQuery/getSavedQueries
  -> "Item Name"     query uid   (items)
  -> "Dataset Name"  query uid   (freestanding datasets)
Query-2006-03-SavedQuery/executeSavedQuery
  {"query":{"uid":"<uid>","type":"ImanQuery"},
   "entries":["Item Name"], "values":["Crack Test*"], "limit":200}
getProperties on every hit -> confirm name and type BEFORE deleting

Give test objects a distinctive, greppable name prefix from the start. It is the only thing that makes cleanup reliable.

Deleting: "the instance is referenced" is expected, just retry

Core-2006-03-DataManagement/deleteObjects on a batch of your own test objects will partial-fail with "The instance is referenced." (code 515110) for any object that is the SECONDARY side of a relation you created earlier. The blocker is the ImanRelation row itself.

The fix that works: just retry deleteObjects on the leftover uids. No separate deleteRelations call is needed. Each pass frees more objects as their blocking relations get swept up by the other endpoint's cascade delete. A real cleanup went 41 -> 11 blocked -> 5 blocked -> 0 in three passes, cascade-deleting 292 dependent form/master/revision/dataset objects along the way.

Different code, different fix: 51007 on delete means the object is inside a structure. Remove the occurrence first (AWC right-click Remove, or the removeObject SOA operation), then delete the now-free item. A free-floating requirement that was never structure-attached deletes cleanly straight away.

Verify the cleanup. Re-run every name search and confirm nFound: 0.

The idempotency re-run is not optional

Re-running a load or a generator against already-populated state is the only thing that exercises the already-populated code path. One re-run of a "successful" generator found a latent NameError that the first run could never reach, because on the first run the target package did not exist so the existence-check loop body never executed. Always do the second run.

Related skills

tc-object-authoring, tc-relations-traceability, tc-query-discovery.


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