Skills
TC Schedule Program Planning
Skill
tc-schedule-program-planning. Author Teamcenter Schedule Manager schedules and IPP&E program structure over SOA. The createSchedule path and the single site preference that silently blocks it site-wide, the root-task lazy-creation gotcha, the coordinator-membership gap, and the Psi0WorkElement precedence-network alternative. Use for schedules, tasks, milestones, WBS, IMP or program-planning work in TC.
Native Schedule Manager over REST works. One site preference decides it.
ProjectManagement-2008-06-ScheduleManagement/createSchedule with a
newSchedules container is the real path and the payload the AWC itself POSTs.
The blocker that looks like a dead transport
createSchedule returning 200 OK with empty output (only
updated: [UserSession]) is not a transport failure and not a payload
error. The real reason is in ServiceData.partialErrors:
code 230305 - The preference "SiteTimeZone" is required to be set for the
Schedule Manager application.
getPreferences(['SiteTimeZone']) shows the preference defined (category
"Schedule Manager", string, single-value, protectionScope Site) but with no
value. In that state Schedule Manager rejects every create, for everyone,
including the native AWC Create button. The AWC's own button creates nothing
either, which is the tell that it is not your code.
Fix: an admin sets SiteTimeZone at SITE scope to a valid zoneinfo
region/city (America/Chicago). Rich client: Edit > Options, search
"SiteTimeZone". A Designer role cannot do it.
After the admin sets it, a client-side refresh does not pick it up. The
running tcserver caches it, and refreshPreferences operations fault 214085/214086
over REST. The user must re-log in so a fresh session/pool reads the value.
Once that happened, the exact same previously-failing payload created real
persisted schedules with zero partial errors.
The generalizable lesson: surface ServiceData.partialErrors in every error
path. Swallowing it is what produced a confident, wrong "the write path is dead
over REST" conclusion that stood overnight.
Two follow-ons for a polished schedule
- Raw
createScheduledoes not add the creator as coordinator. The schedule exists and reads back fine, but does not appear in the AWC's?privilege=coordinator"Not Started" list. Add coordinator membership as part of the push. - The response does not return the root
ScheduleTaskuid (it is created lazily). To hang tasks: load the schedule andgetPropertiesto fetch the root task first, thencreateTaskswithparent = {root uid, type: ScheduleTask}.
What the Active Workspace Gantt can and cannot do
Confirmed with coordinator privilege on a live AW instance:
| Works in AW | Blocked in AW (silent no-op or a toast) |
|---|---|
| Add Task, Add Milestone | Delete (even leaf tasks) |
| Inline rename via the Name-cell editor | Cut / Paste |
| Indent of a last-position row, Outdent | Drag-reorder |
| Planned Start/Finish date-cell edit | Indent of a mid-list row |
| Create Dependency (no link forms) |
Net effect: nesting, reordering and dependency links must be finished in the rich client (2-tier). This is the same relational/hierarchical write block that also stops IPP&E Accomplishment/Criteria/Work-Package creation from the AW browser, while flat adds (Events, Risks, Deliverables) work fine.
Working-calendar gotcha: with a Mon-Fri 09:00-18:00 calendar, a 1-day task starting after 09:00 on the schedule's last day overflows the window and the date edit reverts. Only 0-day milestones hold there. Start full-day tasks at 09:00 or shorten the duration.
The IPP&E alternative: a precedence network
Where native Schedule Manager is blocked, IPP&E Item-rooted objects go in through
the ordinary createAttachAndSubmitObjects engine, because they are just Items:
- Types confirmed deployed:
Wbs0Root,Wbs0Element,Psi0WorkElement,Prg0ProgramPlan,Ipp0IPT. - A real schedule as a
Psi0WorkElementprecedence network: one work element per task, chained by the relationPsi0PredecessorWorkElement(revision to revision, primary = successor, secondary = predecessor). - That relation reads back as a same-named reference property on each
successor revision, so it is machine-verifiable in one
getPropertiescall. Seetc-relations-traceability.
Known gaps on that path:
Ipp0IMPAccomplishmentneeds a required "IMP Element ID" property whose real internal name is unknown;ipp0IMPElementIDis wrong, and the create-input descriptor isIpp0IMPAccomplishmentCreI.- WBS parent/child containment (
Wbs0RoottoWbs0Element) is a BOM structure operation, not a GRM relation.Wbs0ApplRelatedStructis rejected with code- Use the BOM/BVR add-children path. See
tc-bom-structure.
- Use the BOM/BVR add-children path. See
Prg0ProgramPlanfaults "invalid input object" via plaincreateAttachAndSubmitObjects. Program Planning has its own create flow.
IMP master-plan gotcha in AW
Adding an IMP Accomplishment under an Event opens a panel requiring Accomplishment
ID, Name and IMP Element ID. Overriding the auto-generated Accomplishment ID
(for example to "A1") makes the create silently no-op. Leave the auto
ACMxxxxxxxx id and set only Name and IMP Element ID. Even then the create does
not persist in AW; build Accomplishments, Criteria and Work Packages in the rich
client.
Prefer native Schedule Manager once unblocked
Both paths work. Native Schedule Manager is the one that shows up in the Schedule Manager UI and that existing sync code targets; the IPP&E precedence network is the fallback when a site preference or privilege cannot be changed.
Related skills
tc-object-authoring, tc-relations-traceability, tc-soa-payload-shapes,
tc-bom-structure.
Not every blocked tier is the SiteTimeZone tier
EXERCISED on saber2506 (TC 2506) 2026-09-01. The SiteTimeZone story above is real but it
is ONE cause, and reaching for it first cost time here.
On this tier createSchedule never produced 230305 at all. It returned 214022
across five attempts, and an earlier version of this section concluded the payload was
"unsettled". ★ Corrected the same day: the payload was simply WRONG, and once fixed the
real blocker is a licence.
The exact working payload, and the one member that decides it
NewScheduleContainer is 20 required XML attributes (flat JSON members) plus billRate
(NULLTAG) and two optional containers. Types matter and must come from the XSD, not from
guessing: 10 strings, 2 xsd:dateTime, 3 xsd:integer (priority, status,
taskFixedType), 5 xsd:boolean.
{"newSchedules":[{
"billRate":{"uid":"AAAAAAAAAAAAAA","type":"unknownType"},
"stringValueContainer":[], <-- ARRAY. `{}` here returns 214022.
"typedAttributesContainer":[],
"name":"<name>","description":"","id":"","revID":"",
"customerName":"","customerNumber":"",
"startDate":"2026-09-01T09:00:00-04:00","finishDate":"2026-12-18T17:00:00-05:00",
"priority":3,"status":0,"taskFixedType":1,
"published":true,"notificationsEnabled":false,"percentLinked":true,
"isTemplate":false,"isPublic":true,
"type":"Schedule","billCode":"","billSubCode":"","billType":""}]}
⚠⚠ stringValueContainer is a StringValContainer carrying a required @key, and it
still wants an ARRAY, not a map. This is worth stating loudly because the sibling recipe
in tc-object-authoring has the OPPOSITE answer: reviseObjects' reviseInputs is a
PropertyValues, also @key-bearing, and it needs {} while [] faults. A required
@key does NOT reliably predict map-vs-array in this binding. Both were settled by
flipping that one member and re-running, which is a two-minute experiment; do that rather
than reasoning from the other recipe.
What the correct payload revealed, and the wrong conclusion drawn from it
26023 The current user is not licensed to perform authoring functions in Teamcenter.
That was measured as infodba (privileged: true, licence level 5, dba/DBA) in a
session that had just created items, relations and a revision, and written up as
"Schedule Manager is gated by a MODULE licence on that tier".
★★★ That was WRONG, corrected the same hour. license_level is a CLASS, not a ranking.
license_level |
meaning |
|---|---|
| 0 | Author |
| 1 | Consumer |
| 2 | Occasional User |
| 3 | Viewer |
| 5 | Admin |
Read that LOV before interpreting the number:
getInitialLOVValues with lovInput.boName "User", propertyName "license_level".
Level 5 is Admin, and Admin is not Author. The message says "not licensed to perform
authoring functions" and means it literally. Both accounts in use (infodba and
dcproxy) were level 5, which is why swapping between them changed nothing and made the
gate look tier-wide. A third account on the SAME host, same release, same project, at
level 0 with an engineering group and role, created a real Schedule (root task, its
own TCCalendar, and a ScheduleMember at coordinator privilege) and an SSP0ServicePlan,
first try, no payload change at all.
⚠ Why the wrong conclusion survived a control. The control was sound in isolation: a
known-good Document create succeeded in the SAME call that the Service Plan refused, which
genuinely proves the session can write. It does not prove the account can AUTHOR in the
licence sense, because ordinary item creation is not gated the way Schedule Manager and
Service Lifecycle are. The control tested a weaker property than the claim needed. Two
accounts agreeing added nothing either, because they shared the licence class: that is
[[false-corroboration]], not corroboration.
⇒ Before ever calling 26023 a tier or module licence, enumerate the accounts you have
and check license_level on each. It is one getTCSessionInfo per account, and here it
was the difference between "needs an admin licensing decision" and "use the other
credential".
⇒ Two lessons, and the second is the expensive one. Read partialErrors before choosing
which failure you are looking at; and do not let a persistent parse error stand in for a
diagnosis. "The payload is unsettled" reads like a finding and is really an absence of
one: it names no cause, cannot be acted on, and here it was hiding a licence fault that a
single correct request exposed immediately.
The IPP&E fallback carried the capability. Six Psi0WorkElement items chained by
Psi0PredecessorWorkElement produced a real fork/join network (two work elements joining
at a third), each also FND_TraceLink-ed to the deliverable it produces. Confirmed the
skill's claim that it is machine-verifiable in one getProperties call, and worth doing
from a second login: the successor with two predecessors listed both, which is the check
that distinguishes a real network from a create response that merely echoed the input.
Adding tasks: createTasks, and the one type that faults
ProjectManagement-2012-02-ScheduleManagement/createTasks. The root ScheduleTask uid is
in the createSchedule response's ServiceData.updated (it carries schedule_tag pointing
back at the schedule), so the documented "load it separately" step is avoidable.
{"schedule":{"uid":"<Schedule uid>","type":"Schedule"},
"createContainers":[{
"parent":{"uid":"<root ScheduleTask uid>","type":"ScheduleTask"},
"prevSibling":{"uid":"AAAAAAAAAAAAAA","type":"unknownType"},
"otherAttributes":[], "typedOtherAttributes":[],
"name":"<name>","desc":"<desc>","objectType":"ScheduleTask",
"start":"2026-09-01T09:00:00-04:00","finish":"2026-09-25T17:00:00-04:00",
"workEstimate":0}]}
⚠ workEstimate is xsd:integer. Sending "0" as a STRING returns 214022 naming
nothing, exactly like a malformed envelope. Six tasks went in unchanged once it was a JSON
number, and the root task's duration recomputed on its own.
★ Note this tier had SiteTimeZone set all along (the created TCCalendar carries
America/Chicago), so the preference blocker at the top of this skill never applied here.
Three different causes have now worn the same 214022/empty-200 mask on this operation:
an unset preference, a wrong member type, and a wrong licence class. Diagnose, do not
pattern-match.
Generated from skills/tc-schedule-program-planning/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.