Skills
TC Bmide Project Validation
Skill
tc-bmide-project-validation. Make a hand-authored BMIDE template project that BOTH the packaging utility and the BMIDE client accept. Covers the requirements neither tool documents, the two that contradict each other, the one that cannot live in the project at all, what breaks when you split a template, and the error messages that name the stage that noticed rather than the thing that is wrong. Ships verify-bmide-project.ps1, which checks all of them against any project. Use before running bmide_generate_package.bat, before loading a project into the BMIDE client, and for any "failed to load correctly" or "Unable to update the manifest file" investigation.
Derived on Teamcenter 2606 (vm2606), 2026-08-10 into 08-11, across two
independently authored templates, dss4decisionmgmt and xc4programreporting.
Both package and both load in the client. Neither is safely deployed: the
first crashed every tcserver on the tier and was reverted, see the deploy
section below.
The one thing to understand first
Two different tools judge a BMIDE project and they check different things.
Both routes produce identical payloads. Compared entry by entry on name +
uncompressed size + CRC32 across _template.zip, _install.zip and
_icons.zip: zero differing entries. Only container metadata differs (platform
token, folder naming, derived .checksum, machine-stamped
client_<name>.properties, zip container bytes).
⚠ A filename-and-hash comparison of two kits is NOT evidence of equivalence, in either direction. It was used here to claim equivalence, then to claim non-equivalence, and it never supported either. CRC32 over zip entries is the test that does.
⛔⛔ A retracted claim worth keeping visible: this skill briefly said "do not deploy the headless output, a named colleague has evidence it is not equivalent." That colleague had no such evidence and had never said it. It was a fabricated blocker attributed to a real person, and it was persuasive exactly because it sounded careful and cited a source. Before a caveat becomes a blocker in a shared document, check it with the person you are citing.
bmide_generate_package.bat |
the BMIDE client | |
|---|---|---|
| runs | headless, tc_root\bin\ |
GUI, tc_root\bmide\client\bmide.bat |
| catches | XSD faults the client loads happily | model errors the packager never sees |
| edits your source | never | silently, on load |
| needs | install\dc_contributions, feature_<name>.xml, content directly under install\ |
ProjectInfo.xml, Functionality declarations, storage classes, a 4-to-9 prefix, workspace registration |
| ignores | everything in the client column | everything in its own column |
★★ A fix checked against one in isolation can break the other. Declaring a missing storage class satisfied the client and then broke the packager, because the obvious name for it was 30 characters and a POM class caps at 27. Neither tool alone can validate a model. Run both, every time.
Run the checker
powershell -NoProfile -ExecutionPolicy Bypass -File verify-bmide-project.ps1 -ProjectRoot <path> -WorkspaceRoot <ws>
<ws> is tc_root\bmide\workspace\<version> (e.g. 2606000.0.0). Omit it and
the workspace section says so loudly rather than skipping silently.
Exit 0 clean, 1 findings, 2 could not run. 2 is deliberately distinct:
a check that could not run must never read as a check that passed.
The requirements
Packager side
**
install\dc_contributions\**, notpackaging\. The Siemensdecision_supportreference tree carries it underpackaging\only, which is a fair read of that tree and wrong for the utility. Keep one copy.⛔ RETRACTED. There is no skeleton-directory requirement. This said
templates,operations,servicesandworkflowsmust exist or you getCannot read the array length because "<local7>" is null. That is false.Measured two ways, independently, after the claim's own author retracted it: a project created by the 2606 BMIDE client contains exactly
.settings,extensions,icons,installand none of the four; and deleting all four from a working project produces an identical kit, exit 0.The real fix for that NPE was adding
install/dc_contributions(rule 1). Two things changed in one pass and the wrong one was credited.⚠⚠ This is the failure mode this skill should be most careful about. The claim reached here from a colleague's README, was written up as an enforced check, and would have had every reader create four pointless directories. A wrong rule in a shared skill is worse than a wrong note: notes get doubted, checks get obeyed. Re-measure an inherited claim before enforcing it, and when the source retracts one, re-measure the retraction too rather than just flipping the bit.
install\tem_contributions\feature_<name>.xmlis a required input the utility reads, not something it emits. Absent, it throws aFileNotFoundExceptionnaming the exact path. Model it on a real installed template attc_root\install\install\modules\feature_*.xml. Its absence at the directory level is reported asUnable to update the manifest file with new versions, which has nothing to do with a manifest.-dependencyTemplateFolderwants a FLAT folder of*_dependency.xml:tc_root\bmide\templatesortc_data\model. Nottc_root\install, which is nested and produces aFileNotFoundExceptionnaming a template that is in fact installed.
4a. ★★ The packager wraps everything under install/ into install/<template>/.
So project content placed at install/<template>/postinstall/ ships at
install/<template>/<template>/postinstall/, and every
${Teamcenter_root_path}/install/<template>/... path in package.xml misses
by one level.
Put project content directly under install/: install/postinstall/,
install/data/. The wrap then produces exactly what package.xml expects.
⚠ With failonerror="false" this is invisible: postDatabaseUpdate
reports Success and installs nothing. With failonerror="true" it at least
fails loudly. Verify it by reading the entry list of the built
<name>_install.zip, never by looking at the project layout: the layout is
what deceives you.
4b. An id may not be both a packageId and an appId. Deployment Center
refuses to scan the media. Measured on the shipped tc2606_wntx64 kit: 378
packageIds, 462 appIds, intersection 0, with controls both ways
(activeworkspacebom package-only, cm app-only), and 8 of 8 shipped
fnd0_dataModelArtifact packages carry no same-named
application_registry config.
★★ This constrains IDS, not artefact kinds. A package may ship an
application_registry entry under a DIFFERENT id, and may declare multiple
artifacts. The only rule is that no single id appears in both namespaces.
⚠ Corrected 2026-08-12. This used to end "A data-model kit belongs in the
package namespace: ship no application_registry entry", which reads as a rule
about what a package may CARRY. Another session quoted it into a package
descriptor as grounds that a combined data-model-plus-AWC package might be
impossible, and filed it as an open roadmap question. Nothing was failing. The
sentence was bolded, specific, and sat under real intersection-zero
measurements, which is exactly what made it persuasive: see the
unchecked-caveat rule in the workspace CLAUDE.md. The measurement was always
about a collision; the prohibition was never measured.
4c. ★★ bmide_generate_package.bat does NOT purge its output directory, and
reports four of four steps Success while re-shipping whatever the previous
run left there. A stale dc_contributions/application_registry/ survived into
a new kit and would have re-shipped a defect that had just been fixed. Build
into a cleared directory, and check the kit contents, not the step summary.
4d. It resolves its classpath from %FOSS_REPOSITORY_HOME%, %TC_BIN%,
%TC_JAVA_HOME%. In a bare WinRM cmd it dies with
ClassNotFoundException: PackageProjectMain, which reads like a broken
install. Source tc_root\tc_menu\tc_<Env>_Env.bat first, in the same process.
Client side
4e. ★★ The prefix must use a digit 4 through 9. The client refuses Xc0:
"Third party solution providers should use ... the prefix; Customers should
use digits 4 through 9 in the prefix." It is validated in the Properties
dialog, so a non-compliant prefix blocks the load, not the build, and
fixing it means renaming every type and attribute that carries the prefix.
4f. Awp0Search* are TYPE constants, not property constants. Declared as
TcPropertyConstantAttach with a propertyName the client rejects each one
as Undefined constant name; aws2_template.xml declares them as
TcTypeConstantAttach with typeName only. ⚠ This does not reconcile
with the runtime SOA read, where getPropertyConstantValues returns
per-property values that discriminate correctly. Unexplained, and recorded as
unexplained.
4g. LOV{::} is not a valid localization id form. The client reports
The value ... of attribute "id" is invalid, and it appears in no shipped
template. LOVValue{::} and LOVValueDescription{::} are valid.
ProjectInfo.xml, all ~53 keys. Copy from a project the client itself created (File > New), not from another repo. A minimalProjectInfopasses the packager and fails the client, which validates the build fields and refuses its own Properties dialog when they are empty. Project-specific:Codegen.Namespace(equals the template name),ExternalBuild.BasePath.win64(where the project sits on the build host),SoaExternalBuild.BundleVersion. ⚠isAutoGeneratedDescriptionsmust be exactly"true", or BMIDE re-migrates the project on every load, reporting "None found" each time, forever..settings\org.eclipse.core.resources.prefswithencoding/<project>=UTF-8.Functionalitydeclared set must cover the referenced set. Everyfunctionality="X"attribute needs a matching<Functionality name="X" .../>. The client emits oneUndefined Functionalityerror per reference; the packager builds a valid kit without it.formStorageClassNamemust name a declaredTcClass, or the client refuses withthe storage Class ... does not exist.- Template
displayNamemust end in a letter or digit. A trailing)is rejected outright. - Workspace registration. See below. This one is not project content.
★★ If you split a template, two things do not follow the types
Splitting a large model into cascading templates is the right response to a deploy you cannot bisect. Two identity-shaped things break when you do it, and the packager builds a clean kit through both.
1. The <Functionality> declaration does not follow the types that reference
it. A template declares one <Functionality> element, and every
TcStandardType names it via functionality="...". That element references no
type, so a split partitioned on types leaves it in whichever partition it landed
in, and every type elsewhere now points at a functionality its own template does
not declare.
Measured on a 105-type model cut into four: 27, 28 and 29 dangling references
in layers 2, 3 and 4. The client emits one Undefined Functionality named "<name>"
per reference. bmide_generate_package.bat reports four of four steps Success,
and all four kits packaged before anyone noticed.
Fix: each template declares its own functionality and repoints its own types. Declaring the same functionality name in several templates is a different bet and was not tested.
2. A rename renames names, not identities. Renaming a project renames files
and ids and leaves every guid="..." untouched, so four Deployment Center
packages shipped claiming one guid. DC keys on the guid, not the name, so
four packages with one guid are not four packages.
Both are checked by verify-bmide-project.ps1. Both were found by running it on
kits that had already packaged cleanly.
★★★ The requirement that cannot live in the project
The client resolves foundation_template.xml from an Eclipse per-project
persistent property, written at import time:
<ws>\.metadata\.plugins\org.eclipse.core.resources\.projects\<name>\.indexes\properties.index
TEAMCENTER_MODEL_FOLDER
#C:\apps\PLM\tc_root\bmide\templates
AbstractFileRepositoryServiceBroker.initializeServices
project.getPersistentProperty(new QualifiedName("", "TEAMCENTER_MODEL_FOLDER"))
AbstractFileRepositoryProjectImportWizard.persistProperties // writes it at IMPORT
Absent, the client reports:
File Loading Error: Cannot find file "foundation_template.xml" in "null"
and every class in the model cascades off it: 1,264 errors from one missing property in one case, 155 in another.
Fixes, either one:
- Import the project (the wizard writes the property). Opening is not importing.
- Project Properties > Teamcenter > BMIDE > Dependent templates directory =
the flat templates folder, then tick the templates matching your
<include>set. The directory must containmaster.xml.
⚠⚠ ExternalBuild.Templates.Home.win64 in ProjectInfo.xml is NOT this
mechanism. It is present and correct in projects that fail exactly this way. Do
not use it to satisfy yourself the templates directory is configured. That claim
cost two sessions several hours.
⚠ Replacing a project directory wholesale destroys the registration. Sync file-by-file. A project that loaded yesterday will fail this way today if its directory was deleted and recreated.
Name caps: 27 and 32, and the four you do not see
| what | cap |
|---|---|
POM class (TcClass/@className, formStorageClassName) |
27 |
type name (typeName, artifactName) |
32 |
★ Teamcenter derives <base>CreI, <base>SvAI, <base>RevI, so a base type
has four fewer characters of room than it looks like. The error then names
the derived type, which may appear nowhere in your source, so you go looking
for a string you never wrote. Check headroom, not length, and report the base to
shorten.
This is why ...RevMasterS rather than ...RevisionMasterS is load-bearing and
not style.
The errors name the stage that noticed, not the fault
| message | actual cause |
|---|---|
Unable to update the manifest file with new versions |
install\tem_contributions\ missing |
Cannot read the array length because "<local7>" is null |
a File.listFiles() on a directory that is not there. Cause unidentified: it was blamed on missing skeleton directories and that was disproved (requirement 2). install\dc_contributions fixed it in the one case measured, but two things changed in that pass |
Cannot find file "foundation_template.xml" in "null" |
no workspace registration |
The system cannot find the file specified + a path |
genuinely that path |
| the utility's full usage text | any failure, not an argument error |
★ Watch error quality improve as causes are removed: unnamed manifest failure, then an NPE naming nothing, then a path that names itself, then success. The most useless message came second, not first, so "the error got worse" was progress.
★ Count distinct FIRST errors, never the total. 1,264 and 155 were both one root cause. Diagnose from the log, not the console: the console showed the utility's usage text, which reads exactly like an argument error, while the log showed the arguments had arrived correctly.
Provenance rules learned the expensive way
- A client-created empty project beats every other reference. It is the only artefact in this exercise that was unambiguously right.
- A Siemens reference tree is authoritative for STRUCTURE, not for VALUES.
A 2512-era snapshot had a different media-file shape and no
feature_<name>.xmlat all. - Installed form is not project form. A census of all three installed
template media files said
rtm_type=Major, three of three, whole population. A project carriesMain. ★ Counting the entire population of the wrong artefact is still the wrong answer, and a complete census is not a control for having censused the wrong thing. - Two version-looking fields, opposite answers:
SoaExternalBuild.BundleVersionis2606.0.0whilecurrentTemplateVersionstays2512.0_0on the same 2606 tier. Do not make them agree. client_<name>.propertiesis machine-specific (client_idembeds the hostname). The packager writes it on every successful build, so any built tree carries one. Never author, commit, or copy it between machines.
★★ Test the checker, not just the project
Every check in verify-bmide-project.ps1 has been run against known-bad input,
and that found four bugs in the checker itself, all of which reported
success:
- a release-token test written as a calendar-year regex (
^20\d\d), which silently passed2606, the exact value it existed to catch - a missing-element check that crashed under
Set-StrictModeand printed no summary at all, so the run produced neither a pass nor a finding - an em-dash check that matched its own literal
- an index parser that read the first path in the file rather than the one following the key, so it failed a known-good project
None were visible by reading the code.
A checker is not a checker until it has been run against known-bad input. A passing check with the wrong threshold is indistinguishable from a passing check with the right one, until something crosses the gap between them.
Free controls on any Teamcenter install: point the workspace check at a client-created project (should pass) and at a name never imported (should report not registered, which is a different outcome from misconfigured).
⛔ Deploying a template can take the tier down, and the kit will look fine
Measured on TC2606, 2026-08-11. A 105-type template deployed cleanly through
Deployment Center (57 of 57 tasks Success, types verified present by
getTypeDescriptions2 with real and fake controls) and then crashed every
tcserver:
13x "908: SM array to free is not a valid unpacked array" (ScopedPtr.cxx)
FATAL 0xC0000005 STATUS_ACCESS_VIOLATION
each tcserver dying ~1s after "Applying Object Property Policy: XmlPolicy:Default"
262 access-violation dumps in about two hours; zero after reverting the VM
Everything in this skill validates the package. None of it predicts whether the data model is safe for the running server. The kit was correct; the tier still fell over.
Two things follow:
- ★ Make the deploy bisectable. A large model deployed as one template gives you no way to narrow the cause. Splitting it into cascading templates so the next deploy bisects itself is the response that session chose, and it is the right shape.
- ★ Take an offline checkpoint and expect to use it. The revert worked and was the correct call. Budget for it rather than treating it as the unhappy path.
⚠ And weigh the blast radius before asking for a revert on a shared VM: it discards everyone's writes since the checkpoint, not just yours. Ask who else has touched the tier since.
★★ A retraction has to travel, and a check travels further than a note
Requirement 2 above was wrong, and the route it took matters more than the fact:
- its author measured it, wrote it in a README, then retracted it in that file
- I read the pre-retraction version, believed it, and hardened it into an enforced check in this skill
- the check would have failed every project until the reader created four directories that do nothing
Two habits fall out, one for each end:
- When you retract something you have already told someone, tell them. A retraction that lives only where the claim lived reaches only people who go back and re-read, and nobody re-reads a settled question.
- Re-measure an inherited claim before enforcing it, and when the source retracts one, re-measure the retraction too rather than flipping the bit. Both reversals here were correct, and I confirmed each independently before acting.
⚠ A wrong check is worse than a wrong note. A note invites doubt. A check gets obeyed, and obeying it produces four unjustifiable directories and no failure to prompt the question. Be slower to add a check than to add a sentence.
★★ A verified result has a shelf life
Every grounding rule in this workspace is about a claim being true when made. Nothing re-checks whether it is still true when read, and a status report or a roadmap note is read hours or days later by definition.
A deploy here was verified properly, with controls, and reported as shipped. The VM was then reverted and the same verification would have returned the opposite answer within the hour. Nothing about the original verification was wrong.
⇒ Re-verify before a claim is acted on, not only before it is written. On a shared VM with checkpoints, "I verified this" carries a timestamp whether you write one or not. And when you correct such a claim, grep for every artefact carrying it: the same sentence had been fixed in a roadmap item and missed in a weekly report.
Related
tc-deployment-center (what to do with the kit once it builds),
tc-vm-operations, tc-verify-and-cleanup.
Generated from skills/tc-bmide-project-validation/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.