TeamcenterKnowledge

Skills

TC Report Definitions

Skill tc-report-definitions. Author, import, verify and delete Teamcenter ReportDefinitions - the classic Report Builder kind and the Active Workspace "active summary/item report" kind that carries charts and feeds the Reports dashboard tile. Covers the export-then-mutate recipe, the report-id length cap that fails completely silently, the chart-type vocabulary actually available (pie/column/line, no donut), why a saved query reports zero definitions on a tier that has 162, and the empty-string criteria that crashes a tcserver. Use for any TC report, dashboard card, Reports tile, or "my report did not import" investigation.

Two report worlds share the ReportDefinition type, and they do not share a utility:

Kind rd_source Utility
Classic Report Builder (rich client, XSL style sheets) Teamcenter import_export_reports
Active Workspace active summary / item reports (charts, dashboard cards) Active Workspace aw_import_export_reports
Full-text search backed FullTextSearch n/a

Everything below is the Active Workspace kind, verified on TC 2606 (TC2606 VM) 2026-08-07. The rb0reportingaw module supplies it.

Never author from scratch. Export, then mutate.

aw_import_export_reports -export -u=infodba -p=infodba -g=dba -stageDir="C:\kits\rpt" -reportId="AW2312_FMEA_DASHBOARD_RPT_001"

AW2312_FMEA_DASHBOARD_RPT_001 (FMEA Dashboard) is the OOTB worked example worth copying: three pie charts plus a table, which is the shape most dashboards want. Export it, change the values, import it back under a new id.

The file must live at <stageDir>\<reportId>\<reportId>.xml.

aw_import_export_reports -import -overwrite -u=... -p=... -g=dba -stageDir="C:\kits\rpt" -reportId="<id>"
aw_import_export_reports -delete  -u=... -p=... -g=dba -reportId="<id>"

Run inside the TC environment shell (tc_root\tc_menu\tc_Vanilla_Env.bat), and write the XML without a BOM.

The file shape

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!--TC Encapsulation : Mapping X-File-->
<ReportDefinition>
  <Id value="XC0_ENTRY_CRITERIA_001"/>
  <name value="Program Entry Criteria">
    <Text primary="en_US"><Item language="en_US" value="Program Entry Criteria"/></Text>
  </name>
  <Description value=""><Text primary="en_US"><Item language="en_US" value=""/></Text></Description>
  <Class value=""/>  <Type value="0"/>  <Source value="Active Workspace"/>
  <isClassOnly value="false"/>  <QuerySource/>  <PropertySet value=""/>  <Stylesheets value=""/>
  <NoOfParameters value="12"/>
  <Params>   <Param_0 value="ReportChart1_0"/> ... </Params>
  <Values>   <Param_0 value="{&quot;ChartPropName&quot;:...}"/> ... </Values>
</ReportDefinition>

Params names the slots, Values fills them positionally. The vocabulary, read off OOTB:

Param name Value
ReportChartN_0 chart config JSON: {"ChartPropName":"Owner","ChartTitle":"PACs Applied","ChartTpIntName":"pie","ChartType":"pie"}
ReportChartN_1 the grouping property, JSON-quoted: "POM_application_object.owning_user"
ThumbnailChart which chart is the tile thumbnail, e.g. ReportChart1
ReportSearchCriteria the query, e.g. type:ItemRevision
ReportTable1ColumnPropName JSON array of display column names
ReportTable1ColumnPropInternalName_0 / _1 JSON arrays of Type.property, split across two params. The split size is arbitrary: 5+5 in the FMEA dashboard, 6+4 in the Changes dashboard. Only the total has to match the column count.
ReportTitle optional styled title, see the chrome note below
DataProvider / AdditionalSearchCriteria alternative to ReportSearchCriteria, see below

The param set is not fixed. FMEA carries 12 params starting at ReportChart1_0; the Changes dashboard carries 13 and starts with ReportTitle. Params names the slots and Values fills them positionally, so a report only carries the params it needs. Copy the OOTB report whose param set is closest to what you want.

ChartType casing varies in OOTB: "pie" in the FMEA dashboard, "Pie" in the Changes dashboard, while ChartTpIntName is lowercase "pie" in both. Reports authored here use the lowercase form and import fine; treat the casing as not load-bearing but do not "correct" an OOTB file you are mutating. | ReportTable1ColumnDataType | JSON array of STRING / DATE / DOUBLE |

Properties are Type.property and may come from a supertype: POM_application_object.owning_user, WorkspaceObject.object_name, ItemRevision.item_id.

★★★ The report id has a length cap, and over it everything fails SILENTLY

An rd_id longer than about 32 characters makes the import exit RC=0, print nothing, and create nothing. No error, no log, no partial object.

Measured: XC0_PRIMARY_ENTRY_CRITERIA_RPT_001 (34 chars) failed every time. The byte-identical file with the id shortened to XC0_ENTRY_CRITERIA_001 (22 chars) imported immediately. Nothing else changed.

This cost six controlled probes to isolate, because every individual content change imported fine on its own - the failure tracked the id, not the content. Set the id convention before authoring a set of reports and keep it well under 32; a family prefix plus a sequence number eats the budget fast.

Independent corroboration that the cap is real rather than an artefact of the one id tested: OOTB ids sit right under it. AW2312_FMEA_DASHBOARD_RPT_001 is 29 characters and AW_61_00_CHG_DASHBOARD_RPT_001 is 30. Siemens' own naming stops where the measurement says it must.

★★ 32 is a recurring ceiling across this stack, not a quirk of reports. Three unrelated subsystems hit the same number: rd_id here (silent), ScheduleTask.bill_sub_code errors at 33 with fault 515035, and Cameo's seg0Kind truncates at 32 with a tilde. Assume 32 for any identifier or code field unless proven otherwise - and note this one is the only one of the three that fails silently, which is what makes it dangerous.

-overwrite and the read-back rule

RETRACTED 2026-08-08. This section previously said "-overwrite does NOT update an existing report" and told you to delete and re-import instead. That is wrong as a general rule.

Measured on TC2606, 2026-08-08, on XC0_TASK_ATTN_001, which already existed:

aw_import_export_reports -import -overwrite -u=infodba -p=infodba -g=dba -stageDir=<dir> -reportId=<id>
 -> Creating New ReportDefinition [XC0_TASK_ATTN_001 - Tasks Needing Attention] -- Success

Read back by exporting the same id immediately afterwards: NoOfParameters had gone 16 -> 17 and both ReportFilterLargeValue_1_* values were the new ones. The Templates list still returned exactly 1 result for the name, and the report opened on the same uid (AIDAAAbep$kOEC) rendering the new content. So -overwrite updated in place, did not duplicate, and did not re-uid.

The original observation (a re-import that left type:ItemRevision in place) is real but was not isolated to -overwrite; it is indistinguishable from the id-length trap and from a stale client render, both of which were also in play that session. Do not treat -overwrite as broken.

What survives from that finding is the rule underneath it, and it is the important half:

★★ Never conclude an import worked from the exit code, and never conclude it failed from the screen. Export the id straight back and diff the params. Two distinct liars were caught here:

  • the utility, which prints -- Success on the id-length trap while storing nothing;
  • the AWC client, which serves a CACHED render of a report after the definition has changed underneath it. Reloading #/showReport?...&uid=<uid> returned the identical page and the identical Updated: timestamp after a confirmed overwrite. Re-entering through the Templates list picked up the new definition (timestamp moved 07:15 -> 07:18). If you are checking whether an edit landed, navigate in through the list, not by replaying the report URL.

If you do delete and re-import instead, note the recreated report gets a NEW uid, so any dashboard card or bookmark holding the old one points at a deleted object.

Silence is the failure signal

A successful create always prints:

 Creating New ReportDefinition [XC0_ENTRY_CRITERIA_001 - Program Entry Criteria] -- Success

No line means nothing happened, even with RC=0. Treat the exit code as meaningless here.

-log=<file> writes nothing for this utility. The usual "always pass -log to see why a TC utility failed" trick does not apply: no file is created. The printed line is genuinely all the signal there is, so capture stdout and assert on it.

★ Because of that, the only trustworthy verification is a re-read, and the only trustworthy progress measure is a count before and after.

★★ A preference change may not reach the client, even though the database is right

Reports lean on site preferences (REPORT_AW_*, dashboard permissions, and any visibleWhen="{pref:...}" gating a surface that hosts one), so this bites here too.

Measured on TC2606, 2026-08-07, by a parallel session: a preferences_manager -mode=import write landed correctly in the database - a SITE export showed the new value with zero occurrences of the old - while every session, including brand new logins, kept reading the stale value. Active Workspace did too. Administration-2012-09-PreferenceManagement/refreshPreferences2 faulted. Only restarting Teamcenter Server Manager TCDB_PoolA picked it up, because the stale copy lives in the pooled tcserver processes rather than in the session.

Exporting a preference to verify it is necessary and not sufficient: the export reads the database, the client reads the pool.

This does NOT reproduce for every preference, and the difference is unresolved. In the same session that built this skill, a preferences_manager write to Xc0PortAuditEnabled (read by a visibleWhen="{pref:...}") propagated with no restart, verified both ways by rendering; and a SOA setPreferencesAtLocations write to a SUMMARYRENDERING also took effect immediately. The failing case was a preferences_manager write to a SUMMARYRENDERING.

The open question is whether the write path or the preference's role decides it - a registration cached per render context behaves differently from an ordinary value read when a condition evaluates. The evidence favours the latter. Full table and reasoning in tc-awc-stylesheets. Verify the specific preference reached the client rather than assuming either behaviour, and remember a pool restart drops every session on the tier, so warn other sessions on a shared machine first.

Reading reports back: two traps

★★ tc_query_by_type("ReportDefinition") returns 0 on a tier that has 162. A false negative, and it is load-bearing: it is what produced an earlier wrong "TC reporting here is greenfield" conclusion. Use the module's own API instead:

Reports-2008-06-CrfReports/getReportDefinitions
{"inputCriteria":[{"clientId":"x","reportDefinitionId":"*","reportDefinitionName":"*",
                   "category":"*","source":"*","status":"*","contextObjects":[]}]}

★★ Pass "*", never "". Empty-string criteria crashed the tcserver (fault 1003, "Communication with Teamcenter server was lost while an operation was in progress"). It does not return an empty list, it takes the server down. The pool recovered on its own.

The response returns uid/type references only; get the names with getProperties on those uids asking for rd_id, rd_name, rd_source, rd_type, rd_param_names, rd_param_values. Reading rd_param_values back is how you prove a report imported as authored, param for param.

The 2007-01 version of this operation exists and is deprecated - the classic 200-OK-with-nothing trap. Use 2008-06.

Charts: what is actually available

From the AWC reports kit on the tier: pieChart, barChart, lineChart, and a chartType whose observed values are column, line, pie.

There is no donut. donut appears in Active Workspace only as bespoke Multi-Site dashboard component titles (overallStatusDonutChartTitle), not as a report chart type. A donut in a source design either becomes a pie, or it becomes a custom XRT/SWF surface - see tc-awc-custom-tab.

Chrome is MOSTLY not expressible, but "not at all" is too strong. Corrected 2026-08-07 after reading OOTB AW_61_00_CHG_DASHBOARD_RPT_001 off the tier: it carries a ReportTitle param holding

{"TitleText":"Changes","TitleColor":"#000000","TitleDispColor":"","TitleFont":"Segoe UI","TitleDispFont":""}

So a styled title - text, colour and font - does exist in the definition.

★★ CONFIRMED RENDERING 2026-08-08. Previously marked UNCONFIRMED here. The OOTB Changes report (AW_61_00_CHG_DASHBOARD_RPT_001) was rendered and its TitleText painted as a styled title band above the charts. So ReportTitle is real, not just a parameter that exists in a file.

That qualifies the blanket claim that chrome cannot live in a ReportDefinition: a styled title CAN. What still has no representation is classification banners, header bands, action buttons and layout. Anything beyond a styled title needs its own surface.

Dashboards and the Reports tile

Native, no customization required: Reports tile → Manage Dashboard → Add Dashboard, then add report templates (active summary and active item reports; item reports also need a source object), and Share Dashboard with all users or specific users/groups/roles. A "card" on a dashboard is a report template added to it.

The routes, because guessing them costs a session

Verified live on TC2606, 2026-08-08. The Reports location is Reports in the left nav (or the Go to Reports link on the Home page), and it has three tabs on bare page ids:

Tab URL
Dashboards #/showMyDashboard
Templates #/showReportBuilderReports
a rendered report #/showReport?reportType=0&title=<name>&uid=<uid>&reportId=<id>&configure=false

CORRECTED 2026-08-16: "the route is always the bare page id" is too broad. It holds for the Reports pages below. It is FALSE in general: the object route on this same tier is module-qualified and the bare form does not exist at all.

#/com.siemens.splm.clientfx.tcui.xrt.showObject?pageId=<page>&s_uid=<parent>&uid=<object>

#/showObject?uid=... returns "Missing Page" for every object tried, including a plain folder, and that folder is the control that matters: without it, the failure on an exotic type reads as "this type has no page" when the route itself was simply wrong. Read the route off the address bar after clicking through once, per type of surface, and do not generalise from one page family to another.

★★★ The route is the BARE page id. A module-qualified form such as #/com.siemens.splm.reports:showMyReports returns "The requested page does not exist." That 404 is a wrong URL, not a missing workspace grant, and it looks exactly like one. This cost a 33-minute tier rebuild chasing a workspace contribution that was never the problem. If a Reports page 404s, click through the UI once and read the URL off the address bar before concluding anything about configuration. See the retraction in tc-awc-stylesheets.

configure=true on the showReport URL does not open the editor. The editor is the Edit command on the template in the Templates list, which lands on #/createReportTemplate?reportId=<id>&previewMode=false&reportType=0&editReport=true.

Adding a card

From a rendered report: Add to Dashboard → pick the dashboard (My Dashboard / Workflow). Verified end to end: Tasks Needing Attention now renders on #/showMyDashboard as a card reading Total Objects: 17 with its Schedule pie. The card shows only the thumbnail chart, which is the chart named by the ThumbnailChart param, so choose that one deliberately.

Related site preferences worth knowing:

Preference Effect
REPORT_AW_ObjectType_Properties allow-list for TABLE COLUMNS
REPORT_AW_ItemReport_Objects_FilterProperties does NOTHING observable - see the falsification below

★★★ SETTLED: chart grouping is governed by the Awp0SearchCanFilter PROPERTY CONSTANT, not by a preference

This supersedes the "two separate allow-lists" model below, which was half wrong. Measured on TC2606 by the SE-status BMIDE session with getPropertyConstantValues, and it correlates 4 for 4 against my own Chart On enumeration:

property Awp0SearchCanFilter groupable? in the preference?
gov_classification true YES no
priority true YES no
wbs_code false NO YES
bill_code false NO YES

★★★ The two properties that ARE in the preference are the two that do NOT group. So the preference is falsified, not merely unsupported, and on two independent lines: gov_classification groups while never having been in it, and the five properties appended to it were always going to produce zero because they carry CanFilter = false.

The "built-in groupable set" is the set of properties carrying Awp0SearchCanFilter = true.

Not proven for a CUSTOM property. Four stock properties is the strongest evidence available without a deployment, and a BMIDE-defined property setting the constant is untested.

Partially closed 2026-08-16 on vm2606, for a TEMPLATE-supplied property rather than a BMIDE-authored one. IAV0VerifReqmtRevision.iav0VerifMethodCmp, shipped by the iav0verificationmanagement template, reads Awp0SearchCanFilter = false. So a non-stock property does NOT automatically group, and note what kind of property it is: a compound projection (the Cmp suffix), whose storage lives on a separate form. Two others from the same family read false as well (iav0VerificationResultCmp, and stock object_name).

Run with both controls, and they are what make the reading usable:

property Awp0SearchCanFilter role
iav0VerifMethodCmp false the reading
owning_user true positive control: the call works
zz9NotARealPropCtl false fake control: false alone is ambiguous

Consequence worth knowing before promising a dashboard: no chart can group on it, and a dashboard CARD renders only its thumbnail chart. A report over such a property can be a TABLE, and a table report cannot become a meaningful card. If the ask is "put X on the Reports tile as a dashboard", read this constant on X's grouping property FIRST: it decides whether the answer is a report, a card, or a bespoke surface. Worked example: se-process-skills/demos/jpo-f35/stage1b-verification-matrix/reports/.

The documented default is STALE. The 2606 data model report shows gov_classification as Awp0SearchCanFilter = false; the tier says true. A package that mirrored the documentation would have shipped the one value that predicts NOT groupable. Read the constant off the tier, never off the doc.

How to read it:

BusinessModeler-2007-06-Constants/getPropertyConstantValues
  member is "keys", NOT "input"

BusinessModeler-2007-01-... returns fault 214085 "service cannot be registered". Use 2007-06.

★★★ INSTRUMENT CAVEAT, and it is severe: a fake PROPERTY name returns value="false". Not an error, not an absence. On this operation false is indistinguishable from "no such property", so a typo reads as a finding. A fake CONSTANT name is omitted from the response entirely, which is a clean signal - the two axes behave differently.

So every false needs a positive control: confirm the property exists by some independent route before believing the value. The four readings above are trustworthy only because wbs_code and bill_code demonstrably exist as rendered table columns.

Retracted from my own notes: wbs_code is NOT a candidate probe property. It reads IsIndexed = false, so it is predicted not searchable and fails two gates exactly like bill_code. My earlier "it returns 38, not 33" hint was wrong - that was somebody's expectation, never a measurement.

⚠ Superseded: "those two are SEPARATE ALLOW-LISTS"

This is the reason behind the most confusing symptom in report authoring: a property renders happily as a table column and is invisible to every chart and filter. It is not a quirk of the property, it is two independent preferences. Found by the SE-status-reports session on TC2606, 2026-08-08, and it explains a whole afternoon of wrong guesses on my side.

Measured live. ScheduleTask.bill_code and .wbs_code rendered fine as table columns, while:

  • <chart on bill_code> was impossible: bill_code is absent from the Chart On dropdown
  • ReportSearchCriteria = type:ScheduleTask AND "Bill Code":* returned zero rows

The tier's values explain both exactly:

REPORT_AW_ObjectType_Properties                 ...  ScheduleTask:{item_id}          <- columns, present
REPORT_AW_ItemReport_Objects_FilterProperties   WorkspaceObject:{object_type,owning_user,last_mod_user,owning_group}
                                                GroupMember:{role,default_role}
                                                DocumentRevision:{fnd0NextReviewDate}
                                                                                     <- NO ScheduleTask line

Both are Site scope, array=true. Format is ObjectType:{Property1,Property2} using internal names, per the preference's own description ("Defines Object properties for Grouping Report Data ... User can select properties to create Charts").

★★★ So do not read the Chart On dropdown, or the Search Data facet list, as "what the engine supports". They are "what the allow-list currently permits". I enumerated both and treated the result as a capability limit, which sent me looking for syntax errors in a criteria string that was fine. The built-ins you see plus whatever arrives from the WorkspaceObject line is the whole story.

★★★ The three gates PROVEN on one screen, and a working carrier for custom dimensions

Verified 2026-08-08 by rendering a probe report against a single pilot ScheduleTask that carried the same value twice, once in a groupable property and once in a display-only one:

property value surface it reached
gov_classification Load Lower Skin chart dimension - pie drew with that slice
ip_classification Make - AMO Routed chart dimension - pie drew with that slice
bill_sub_code / bill_type the same two values table column only

One screen, both outcomes, same data. And an independent positive control settled the searchable gate without a report at all: a global AWC search for type:ScheduleTask AND "Government Classification":* returned 1 results found, exactly the one pilot object it had been set on.

★★ So gov_classification and ip_classification are a WORKING CARRIER for a custom reporting dimension on ScheduleTask: settable post-create, searchable, groupable. If you need a dimension the OOTB set does not give you, ride one of these rather than inventing a property - a bespoke field lands in the displayable gate only and can never chart or scope. Projects is the other strong candidate on the groupable list, though creating org-level TC Projects needs privileges worth escalating for deliberately.

Setting a carrier property: three mechanics that each cost a cycle to find

Measured by the SE-status-reports session while populating 33 tasks, and worth having together because you hit all three in one sitting.

★★ setProperties takes a MAP, not an array. Core-2007-01-DataManagement/setProperties with attributes as [{name, values}] faults 214022. The working shape is Map<String, VecStruct>:

{"objects":    [{"uid": "...", "type": "ScheduleTask"}],
 "attributes": {"gov_classification": {"stringVec": ["Load Lower Skin"]}}}

★★ 214022 "An error has occurred during the JSON parsing" is a CLASS, not a clue. It bit three different call shapes in one afternoon: this one, setPreferencesAtLocations with "object": null instead of omitted, and a guessed getReportDefinitions struct. It means your struct is wrong somewhere and the message will never tell you where. Read the shape off the services reference rather than iterating.

★★ A property can be settable post-create and rejected at create. otherAttributes on createTasks refuses gov_classification with fault 38015 (not on the ScheduleTaskCreI descriptor), yet setProperties sets it happily a moment later. The create-descriptor allow-list and the writable-property set are two different things. That is the same shape as the report allow-lists and the three gates: Teamcenter gates by surface, repeatedly, and enumerating one surface tells you nothing about another. Create first, then set.

setProperties applies the SAME value map to every object in objects[]. Per-object values therefore need one call per distinct value, batched by value group - 5 calls covered 33 tasks across 5 Segments. Plan the write as a group-by, not a loop.

bill_code, bill_sub_code, bill_type, wbs_code and fnd0ExternalID remain display-only even with the FilterProperties line added, because they fail the searchable gate. That asymmetry is the whole point of the three-gate model.

Authoring trap found building that probe: a summary report needs its table-column internal names split across ReportTable1ColumnPropInternalName_0 AND _1. A probe carrying _0 only failed every render with:

INVALID FIELD: Expected string, not undefined --performSearchViewModeInput.0.searchInput.attributesToInflate.4

and the fault survived a cold pool, so it was real rather than cache. Mirroring a known-good report's _0 (three names) plus _1 (one name) split fixed it. Copy the parameter shape of a report you have watched render, rather than composing a minimal one.

★★ Append, never replace. It is an array preference and the OOTB WorkspaceObject, GroupMember and DocumentRevision lines must survive, or you silently remove grouping dimensions other reports depend on.

And it is a preference, so it is cached in the tcserver pool like every other one. Writing it and rendering on a warm pool tells you nothing. See tc-awc-stylesheets for the settled finding and the pool-age discipline; the same rule applies here. Verify by effect after a recycle: does the property appear in the Chart On dropdown, not does the export show the new value.

★★★ THREE gates, not two: searchable / groupable / displayable

The allow-lists above are only two thirds of it. A property must clear a different gate for each surface, and a property can pass one and fail the others. Model due to the SE-status-reports session, measured on TC2606 2026-08-08:

Surface Gate How it fails
ReportSearchCriteria ("X":*) the property must be searchable AWC states it: Your search was not performed because "bill code" is not a searchable property name.
chart grouping / filters REPORT_AW_ItemReport_Objects_FilterProperties absent from the Chart On dropdown
table columns REPORT_AW_ObjectType_Properties column simply does not render

★★ ScheduleTask.bill_code, .bill_sub_code, .bill_type, .wbs_code and .fnd0ExternalID pass only the third. They can be table columns and nothing else, even with the FilterProperties line added. So they cannot scope a report and cannot be a chart dimension.

The properties that ARE groupable on ScheduleTask (full Chart On list, read on a pool that had loaded the preference, so this is the real set rather than a scroll-truncated view):

Type, State, Status, Priority, Start Date, Finish Date, Work Complete Percent, Task Type,
Owner, Schedule, Group ID, Actual Start Date, Actual Finish Date, Is Template Task,
Schedule Summary Task, Is Baseline, Release Status, Date Released, Last Modifying User,
Date Modified, Projects, Government Classification, IP Classification, In Process,
Suspect, Site Name, se_version

★★ If you need a custom dimension, carry it in one of those rather than a bespoke property. Projects is the strongest candidate: TC project membership is a first-class concept with real API support, not a repurposed string field. Government Classification and IP Classification are in the list but their settability at create time is untested - gov_classification was in an otherAttributes probe that failed, though the error named a different property.

⚠ Deliberate tier drift on TC2606, recorded so nobody mistakes it for residue

REPORT_AW_ItemReport_Objects_FilterProperties on TC2606 carries an appended line that is not OOTB:

ScheduleTask:{bill_code,bill_sub_code,bill_type,wbs_code,fnd0ExternalID}

It was added 2026-08-08 to test whether the preference alone makes those properties groupable. It does not - see the searchability gate above; they never appear in Chart On. It is left in place because it is additive, the three OOTB lines (WorkspaceObject, GroupMember, DocumentRevision) are intact, and one open hypothesis may still need it: the preference is named REPORT_AW_**ItemReport**_Objects_FilterProperties and its description says the properties become available during Item Report authoring, while every report here is a Summary Report (Type 0).

That hypothesis is now FALSIFIED, on the preference's own shipped default. Its OOTB value includes GroupMember:{role,default_role}, and a GroupMember is not an ItemRevision and cannot be the source object of an Item Report. So "ItemReport" in the name denotes the AWC authoring surface, not the type the report operates on, and the preference is not report-type-scoped.

Consequence: ReportSearchCriteria decides the type, not this preference. Do not design around putting properties on a revision "so an Item Report can reach them" - that reasoning is void.

Strip the appended line freely if you are cleaning up; nothing depends on it. Falsification due to the SE-status BMIDE session, from the shipped default rather than an experiment.

⚠ A property can be groupable while in NEITHER the preference NOR the documented constant

Measured, and it constrains every explanation offered so far. ScheduleTask.gov_classification:

in the Chart On dropdown YES - one of the 28, read on a pool that had loaded the preference
in REPORT_AW_ItemReport_Objects_FilterProperties NO - the appended line was {bill_code,bill_sub_code,bill_type,wbs_code,fnd0ExternalID}, which never contained it
searchable in ReportSearchCriteria YES - "Government Classification":* returned rows

★★ So the preference did not make it groupable, and something else did. The same holds for Priority, State, Task Type and Schedule - all in the 28, none in the preference. There is a built-in groupable set that owes the preference nothing, which means "does the preference work" and "is this property groupable" are two different questions with possibly different answers.

The candidate mechanism is the Awp0Search* property-constant family (Awp0SearchIsIndexed, Awp0SearchIsStored, Awp0SearchCanFilter, settable per property in BMIDE). It does not obviously fit either: gov_classification is documented as Awp0SearchCanFilter = false yet is demonstrably groupable. Three readings survive and none is measured - the constant governs AWC search facets rather than report chart grouping, or this tier's actual constant differs from the documented default, or something else again.

The next measurement is cheap and nobody has taken it: read the ACTUAL constant value for gov_classification on the tier, rather than the documented default. If it really is false while the property groups, the constant is not the mechanism for chart grouping and thirty lines of BMIDE constants are inert.

★★ ReportDefinitions are cached in the tcserver pool

Editing a report and seeing no change is not evidence the edit failed. Measured 2026-08-08: XC0_PRI11_ENTRY was reverted to a previous ReportSearchCriteria, verified by export read-back, and the Report Builder edit page still displayed the reverted-away criteria until the pool recycled.

★★★ This is the third artifact type found behind that cache, after preference values and parsed style-sheet content. Treat it as the general rule rather than a growing list: assume anything the pool has already read is cached, and verify by effect after a recycle. The corollary that keeps catching people is that a measurement taken minutes after a restart proves nothing about caching, because a cold cache makes a broken write look fixed. Record pool age beside any such observation:

(Get-Process tcserver | Sort-Object StartTime | Select-Object -First 1).StartTime

| REPORT_Create_Dashboard_Allowed_GroupRoles | who may create dashboards |

★ To put a Reports tab on a business object that lacks one, inject one line into its summary style sheet: <inject type="dataset" src="Rb0InContextReportsSubLocation"/>. See tc-awc-custom-tab for the mechanics of editing a summary XRT safely.

★★★ ReportSearchCriteria is NOT limited to type:X

Both the FMEA and QA samples use a bare type: string, which makes it look like the only form. It is not. OOTB AW_43_00_ADV_SUM_RPT_001 ("My Modified Objects", live on the Home dashboard) carries a full boolean query with session tokens:

ReportSearchCriteria            "Last Modifying User":$ME AND ("Date Modified":$TODAY OR "Date Modified":$YESTERDAY)
ReportTranslatedSearchCriteria  (V_A_L_0:$ME) AND ( (V_A_L_1:$TODAY) OR (V_A_L_2:$YESTERDAY) )
ReportTranslatedSearchCriteria  V_A_L_0:POM_application_object.last_mod_user
ReportTranslatedSearchCriteria  V_A_L_1:POM_application_object.last_mod_date
ReportTranslatedSearchCriteria  V_A_L_2:POM_application_object.last_mod_date

So the criteria is two-layer: a human-readable expression using display names, plus a ReportTranslatedSearchCriteria block that binds V_A_L_n placeholders to real Type.property paths and restates the expression against them. $ME, $TODAY and $YESTERDAY are session tokens.

★★ rd_parameters may repeat a name. ReportTranslatedSearchCriteria appears four times in that one report. Slots are positional, not unique, so any code that builds a name-to-value map by indexOf silently keeps only the first and drops the rest. Build a positional list, not a map.

A bare type:ScheduleTask pulls every schedule task on the tier, including other teams' schedules. Copy the two-layer shape from AW_43_00_ADV_SUM_RPT_001 rather than inventing syntax.

But this is NOT the normal way to narrow a report, and reaching for it first is the mistake. See the next section: filters are a separate, far simpler mechanism, and they are what the Report Builder UI actually writes.

★★ A WILDCARD in ReportSearchCriteria is how you scope by name

ReportFilter_<n> (next section) is facet-value based and cannot express a prefix match. When you need "everything whose name starts with X", put it in the criteria instead:

ReportSearchCriteria    type:IAV0VerifReqmtRevision AND "Name":VM-MSP2-SR-*

Measured on vm2606 2026-08-16: 47 rows before, 39 after, with another programme's rows gone and nothing else changed. No ReportTranslatedSearchCriteria and no DataProvider needed.

★★★ Why this matters more than it looks: a bare type:X criteria is TIER-WIDE, and it reads correct for exactly as long as your data is the only data of that type. A report here was named "MSP-2 Verification Matrix", carried type:IAV0VerifReqmtRevision, and rendered 37 rows for over a week. Another session then authored a second programme and the same report silently rendered 47, mixing two programmes under a name that claims one. Nothing errored and nothing looked wrong. If a report's NAME claims a scope, its CRITERIA has to enforce that scope; otherwise the name is a promise the query does not keep.

⚠ The utility may print Creating New ReportDefinition on an -overwrite of an existing id, which reads like delete-and-recreate and would mean a NEW uid and a broken dashboard card. It did not: the report came back on the same uid. Check the uid, not the verb.

★★★ How to build a FILTERED report

The filter is not part of ReportSearchCriteria at all. It is a separate set of parameters, and this is the single most useful thing in this file. Captured 2026-08-08 by building the filter in the AWC Report Builder UI and then exporting the definition to see what the server stored.

ReportSearchCriteria stays the bare type:ScheduleTask. Alongside it:

ReportFilter_0              ScheduleTask.fnd0state
ReportFilterLargeValue_0_0  {"searchFilterType":"StringFilter","stringValue":"not_started",
                             "stringDisplayValue":"Not Started","colorValue":"","startDateValue":"",
                             "endDateValue":"","startNumericValue":0,"endNumericValue":0,
                             "count":0,"selected":false,"startEndRange":""}
ReportFilter_1              ScheduleTask.priority
ReportFilterLargeValue_1_0  {"searchFilterType":"NumericFilter","startNumericValue":5,"endNumericValue":5,
                             "stringValue":"5", ...}
ReportFilterLargeValue_1_1  {"searchFilterType":"NumericFilter","startNumericValue":4,"endNumericValue":4,
                             "stringValue":"4", ...}

The grammar, and it is the whole thing:

  • ReportFilter_<n> names ONE property to filter on, as a real Type.property internal name.
  • ReportFilterLargeValue_<n>_<m> is one selected VALUE on that property, as an escaped JSON blob. The <n> must match its ReportFilter_<n>.
  • Several _<m> on the same <n> = OR. Different <n> = AND. The example above is state = Not Started AND (priority = 5 OR priority = 4), and it returned exactly 17 of 92.
  • Every key in the blob must be present even when unused; copy the full shape above and change only the fields the filter type uses.
  • searchFilterType seen so far: StringFilter (uses stringValue + stringDisplayValue) and NumericFilter (uses startNumericValue / endNumericValue). Date facets exist in the UI, so a DateFilter almost certainly follows the startDateValue / endDateValue pair.

★★★ A NumericFilter written as a RANGE filters correctly but silently corrupts any chart on that same property. Measured: startNumericValue:4, endNumericValue:5, stringValue:"4" returned the correct 17 rows, and the Priority pie rendered a single bucket labelled "4 (High)" covering all 17 when 12 of them are Very High. The chart takes its bucket from the filter's stringValue. Writing it the way the UI does, as two discrete single-value entries, gave the correct 12 / 5 split with the same 17 rows. Use one entry per value, never a range, whenever a chart groups on that property.

Two things a hand-authored filtered report does NOT need

Proven by authoring XC0_TASK_ATTN_001 from scratch with neither, importing it, and rendering it: 17 rows, three correct pies, populated table.

  • No ReportTranslatedSearchCriteria. The UI writes V_A_L_n bindings when it saves, but they are not required for a report to resolve and render.
  • No DataProvider. The UI stamps Awp0FullTextSearchProvider; omitting it is fine.

Both are worth knowing because copying an OOTB export drags them along, and one of them (CAE0MDOInputsTableRow.cae0InputType, generated by the UI as a binding for "type") is nonsense you do not want to inherit.

The fastest way to get the vocabulary for a type you do not know

Do not guess property names. Open the Report Builder on any report of that type, click Search Data, then the funnel icon: AWC lists every filterable facet with live counts, and the Chart On: dropdown lists every chartable property. Click the facets you want, save, then export the definition and read what it wrote. On ScheduleTask this returned Type, State, Status, Priority, Start Date, Finish Date, Work Complete Percent, Task Type, Owner, Schedule, Group ID, Actual Start Date and Actual Finish Date, which is a better map than any doc.

★ The Report Builder header shows the two clauses separately once a filter is applied: Criteria: type:ScheduleTask Filters: State=Not Started, Priority=5 (Very High), 4 (High). If the Filters half is missing from that header, nothing was stored.

One query per report, and the data-provider escape hatch

★★ A report carries exactly ONE ReportSearchCriteria, shared by every chart and the table. Confirmed on AW2312_FMEA_DASHBOARD_RPT_001: the criteria is the bare string type:Qfm0FMEANode and all three pies group on properties of that one type.

Consequence worth planning around: a source dashboard whose blocks span more than one business object type cannot be one report. It decomposes into several, or it becomes surface work. Settle that before promising a report count against a set of designs.

★★ A report can be backed by a named DATA PROVIDER instead of a type query. OOTB AW_61_00_CHG_DASHBOARD_RPT_001 leaves ReportSearchCriteria empty and carries instead:

DataProvider              = Cm1MyChangesProvider
AdditionalSearchCriteria  = {"changesProviderContentType":"Dashboard"}

This is the route for a report whose rows are a shaped rowset that no single business object provides - crosstabs, KPI rails, anything joining across types. It moves the work from report authoring to SWF module work (authoring the provider), so price it accordingly, but it means such blocks are not automatically conceded to bespoke XRT.

★★ The report TYPE renders - watched, not inferred, 2026-08-08. AW_61_00_CHG_DASHBOARD_RPT_001 was opened and laid out correctly: styled title band, three chart frames (Type / Creation Date / Maturity) and a Contents table with its real columns.

It does NOT prove a provider can supply rows. Every chart read "No data to display", which is correct behaviour rather than a failure: Cm1MyChangesProvider is user-scoped and the logged-in user had no changes. So what is established is that a DataProvider-backed definition is well-formed and paints; what is still unproven is a provider returning a populated rowset. Do not quote this as "DataProvider reports work" without that qualification.

★★★ A CROSSTAB needs the CLASSIC report, not the Active Workspace one

EXERCISED on vm2606 (TC 2606) 2026-08-16, rendered and read back out of the DOM.

An Active Workspace report definition can only declare columns (Type.property). It has no crosstab, no column width, no wrap, and the user cannot resize a report table from the UI. So the moment someone asks for a matrix with marks in cells, or complains that a column truncates, the AW kind is the wrong tool and no amount of parameter tuning fixes it.

The classic kind (rd_source = Teamcenter, utility import_export_reports, not aw_) hands a PLMXML document to an XSL stylesheet, so the output shape is entirely yours: arbitrary HTML, any table, any styling. 102 of the 163 definitions on a stock 2606 tier are this kind.

The file layout, both parts required

<stageDir>\<reportId>\<reportId>.xml
<stageDir>\<reportId>\Resources\<stylesheet>.xsl

The definition points at the stylesheet by file name:

<Type value="0"/>                        <!-- 0 Summary, 1 Item, 2 Advanced -->
<Source value="Teamcenter"/>
<QuerySource>
  <ImanQueryDefinition>                  <!-- inline; the import CREATES the saved query -->
    <class value="ItemRevision"/>
    <clauses_real>SELECT qid FROM ItemRevision WHERE "object_name" = "${Name = *FOO-*}"</clauses_real>
    <uniqueid value=""/><iflag value="0"/><rtype value="0"/>
  </ImanQueryDefinition>
</QuerySource>
<PropertySet>
  <Name value="XC0_MyProps"/><Scope value="0"/><NoOfClauses value="2"/>
  <Clauses>
    <clause_0 value="CLASS.ItemRevision:PROPERTY.object_name:DO"/>
    <clause_1 value="CLASS.MyRevision:PROPERTY.myProp:DO"/>
  </Clauses>
</PropertySet>
<Stylesheets>
  <Stylesheet><StylesheetType value="CrfHtmlStylesheet"/>
              <StylesheetName value="MyStyle.xsl"/></Stylesheet>
</Stylesheets>

A query-driven Summary Report carries no Params/Values block at all (unlike the AW kind and unlike the Method::DispatcherRequest Advanced Reports). Copy TC_2007_00_SUM_RPT_0003 ("Admin - Object Ownership"): it is the OOTB worked example of query + PropertySet + HTML XSL.

★★ The stylesheet input contract

Read it off a shipped stylesheet rather than guessing:

/plm:PLMXML/*[@id]                                       one element per result object
  plm:UserData/plm:UserValue[@title='<property>']/@value  each exported property

Namespace plm is http://www.plmxml.org/Schemas/PLMXMLSchema, the transform is XSLT 1.0 (no for-each-group, no exsl:node-set unless you declare it), and criteria_count / search_criteria arrive as xsl:param.

Which properties appear is decided by the PropertySet, not by the stylesheet. A missing clause_n shows up as an empty cell, which reads exactly like missing data.

A COMPOUND property does survive the export. iav0VerifMethodCmp, a projection whose storage lives on a related form, came through populated on 37 of 37 objects. This was genuinely uncertain beforehand, so the stylesheet was written with a fallback AND made to count and print which path fired. Do that: a fallback that silently carries the whole report reads as working until the day the primary path matters.

Teamcenter rewrites the query on import. WHERE "object_name" = "${Name = *FOO-*}" came back out of the database as ... LIKE .... Harmless, and a reminder that export-and-diff is the only honest confirmation even when the utility prints Success.

Two traps that cost time

Re-opening the template serves the PREVIOUS render. After changing a stylesheet you must hit Generate again; simply selecting the template in the list showed the old HTML. Same cache trap this skill records for the AW kind, and it applies to the classic kind too.

The report renders INSIDE Active Workspace, in a Reports tab beside Overview on the template, in an iframe. So get_page_text on the page returns the template list and not one word of the report. Read iframe.contentDocument instead, which is also far cheaper than chasing the inner scroll region with screenshots.

★★ Test the stylesheet WITHOUT Teamcenter first

Import, render, screenshot is a slow loop and it can only ever be run against good input. Build the PLMXML yourself and run the transform locally (lxml.etree.XSLT), with controls:

  • the real shape, diffed cell for cell against whatever the report is supposed to reproduce;
  • the risky property removed, so the fallback path is actually exercised;
  • a known-bad case aimed at your join. A name-based join on FOO-1 will happily swallow FOO-11's rows unless the prefix ends in a separator, and that bug produces a plausible fuller-looking table rather than an error.

Worked example: se-process-skills/demos/jpo-f35/stage1b-verification-matrix/, files reports/XC0_MSP2_VCRM_XT_001/ and preflight_xsl.py.

★★★ Making one of these REUSABLE: bind identity to TYPE, pairing to name

Two different questions, and answering both with the object name is the trap:

question answer it with
what IS this object object_type (export it in the PropertySet, then compare)
which object goes with which a naming convention, if you must, because the PLMXML carries objects and NOT the relation between them

Measured failure, 2026-08-16. A crosstab was generalised off a name rule: "a verification requirement is anything named VM-*, a requirement is everything else". The local preflight passed every control. The live run returned 234 rows instead of 22, because the query also matched the verification requests, simulation requests and tests that carry the requirement id in their names, and "everything else" swept every one of them in as a blank requirement row.

Not one mark was wrong. What was wrong was what a ROW IS, and 212 blank rows read as a catastrophic verification gap that the programme did not have. Note the direction: the defect made the report more alarming, not less, so nobody would have dismissed it as noise. They would have believed it.

Three habits that come out of this, and the last two generalise past reports:

  1. Select on object_type, and expose the type names as xsl:param so a site can set them rather than edit XPath.
  2. Print the scope on the report. search_criteria is handed to the stylesheet; render it. A crosstab cannot be read without knowing what was in scope, and an over-broad filter is invisible in the table itself.
  3. Count the rows that contribute nothing, and say when they are the majority. "212 of 234 requirements have no verification requirement at all" is a sentence that stops a reviewer; 212 silently blank rows is a sentence that misleads one.

And note what the preflight could NOT catch. Synthetic fixtures contain what you thought to put in them, so a fixture built from requirements and verification requirements alone cannot discover that the real query also returns three other types. Local controls catch logic errors; only the live run catches wrong assumptions about what comes back. Add the surprise to the fixture afterwards so it stays caught, and keep a positive control that fails if the fixture noise is ever dropped.

Say what a cell means

A crosstab silently aggregates. 37 trace links produced 36 marks in the worked example, because one requirement is verified by the same method under two techniques and they share a cell. That looks like a missing link to anyone reconciling the two numbers. Print the rule in the report.

Reports can only query Teamcenter

ReportSearchCriteria is type:<BusinessObject>, and every chart and column is a Type.property on TC data. A field that lives in an upstream system is not reportable until it exists in Teamcenter as a typed property. Recreating a BI dashboard as a TC report is therefore usually a data-ingest problem wearing a reporting hat: settle where each source column will live in the TC data model before authoring, or you will author 28 reports against fields that cannot resolve.

Cleanup

-delete -reportId=<id> per report, then verify by counting definitions through getReportDefinitions, not by trusting the list of ids you kept. Six probes created during one investigation went 162 → 168 → 162.

Related skills

tc-awc-custom-tab (custom surfaces, XRT injects), tc-awc-stylesheets, tc-query-discovery (why a saved query returns zero), tc-soa-payload-shapes (the 200-OK-empty class of failure), tc-verify-and-cleanup.


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