Implementation Plan: core-hr-transaction-bundle¶
Summary¶
Configures five new named transactions against Nova's existing transaction framework
(TransactionContextRunnerService + Decision Table routing in nova-corehcm-sn-app,
orchestrated by nova-corehcm-agent's decision node) — Personal Data Updates, Job Data
Changes, Promotion, Demotion, and Salary Changes. Bonus and Incentive Awards (originally
a sixth) is deferred out of this build pass — decided, not just flagged: it has no
existing home in nova-compensation-sn-app's schema, and rather than pulling that app's
team in as a stakeholder now, it's skipped (see spec.md's Out of Scope). None of the
five is a new service or a new architectural pattern; each is a new intent + entity
schema + Decision Table + context-script config on top of what already runs department
transfers and manager changes today.
Salary Changes crosses a domain boundary the spec didn't originally account for. This is
resolved by reading nova-compensation-sn-app's actual source directly (see
schema/compensation-schema.md): it calls WorkerCompensationService.upsertCompensation()
— a cross-scope-public script include already live in that app, upserting
x_novaw_comp_worker_compensation by (worker, effective_date). No new REST endpoint,
table, or service is needed.
Promotion and Demotion are primarily nova-corehcm-sn-app transactions (job level,
title, and Job Assignment are entirely Core HR-owned), but both also trigger a
compensation-band change — that write goes through the same
WorkerCompensationService.upsertCompensation() cross-scope call as Salary Changes, not
a separate mechanism. Three transactions touch nova-compensation-sn-app, not one.
Spec is status: draft with several genuine open items (document/attachment reference,
job-description storage location, multi-jurisdiction tax, Bonus/Incentive Award schema)
— none of these are stated by the spec owner as blocking, so this plan proceeds to
ready-for-exploration. They're carried into Open Questions below and should be settled
during schema-changes.md drafting, before the schema-first gate is signed.
test-plan.md now exists alongside this plan — 21 Given/When/Then scenarios expanding
spec.md's Acceptance Criteria per transaction, plus a Cross-cutting group covering the
compensation-write role check, the RCA cross-scope-privilege check, and the missing
hrbp test account, all sourced from this plan's own Risk Flags. Several scenarios are
explicitly marked blocked on the same Open Questions listed below — Nova Developer
should treat it as the acceptance-level source of truth, not re-derive scenarios from
scratch.
End-to-End Flow¶
A Direct Manager proposes a Salary Change for a report → it's validated, routed for approval, and on approval the change lands on both the Core HR job/worker record and the compensation record, with the worker notified.
sequenceDiagram
participant Mgr as Direct Manager
participant SA as nova-superagent-agent
participant CA as nova-corehcm-agent
participant SN as nova-corehcm-sn-app
participant HRBP as HR Business Partner
participant Comp as nova-compensation-sn-app
participant Worker as Worker
Mgr->>SA: submit salary change request
SA->>CA: dispatch HR transaction task
CA->>SN: validate inputs against Core HR schema
SN-->>CA: validation passed
CA->>SN: evaluate Decision Table for salary change
SN-->>CA: requires approval, route to HRBP
CA->>SN: create task and approval record
SN->>HRBP: approval task assigned
HRBP->>SN: approve with stated reason
SN->>SN: run ordered context scripts for salary change
SN->>Comp: update worker compensation record
SN-->>CA: transaction complete via Kafka event
CA->>Worker: notify approved change and effective date
Design Decisions¶
- Configuration, not new services. All five transactions reuse the existing
TransactionContextRunnerService/ Decision Table pattern already live for department transfers and manager changes — this Feature adds five new named transaction configs, not new infrastructure. - Deterministic vs. approval-gated is set per transaction, not uniformly. Personal Data Updates' address/contact path is the only fully deterministic (no-approval) path among the five; every other path routes through at least one human approval, per each transaction's own policy (see spec.md Scope).
- Compensation writes cross a scope boundary via an existing public script include —
and three transactions need it, not one. Salary Changes', Promotion's, and
Demotion's execution scripts all call
new x_novaw_comp.WorkerCompensationService().upsertCompensation({worker_sys_id, effective_date, base_salary})directly — confirmed by readingnova-compensation-sn-app's source (WorkerCompensationServiceWrapper.js,accessibleFrom: 'public'). This is the same public-wrapper/package_private-impl patternnova-corehcm-transaction-creation's skill documents forWorkerService/JobService, just cross-scope. Promotion and Demotion stay primarilynova-corehcm-sn-apptransactions (job level/title change) — the compensation write is one step inside their execution script, not a separate transaction. Role gotcha (applies to all three): the table's write ACL grantsx_novaw_comp.hr_opsandx_novaw_comp.integration_writer(create alsointegration_creator) — notably not the genericx_novaw_comp.agentrole used elsewhere in the platform. Confirm which role the execution script's session runs as; if it's a generic agent role, the write will fail ACL, not just silently no-op. - New transaction-framework skill now exists and is auto-loaded.
nova-corehcm-transaction-creation(installed this session,.github-private/claude/skills/) documents thetransaction_configuration→ context script → execution script anatomy, thectx/ctxJsoncontract,CoreHRConstantstable lookup, and the IIFE return-value pattern —nova-developer-sn.md's Phase 1b now reads it automatically whenever the target repo uses this framework. All six transaction configs (plus the cross-scope compensation calls above) should follow its boilerplate rather than being built ad hoc from generic Business Rule/Script Include patterns. - Bonus and Incentive Awards is deferred, not built this pass — decided.
x_novaw_comp_worker_compensationhassign_on_bonus(one-time) but nothing resembling a target/actual incentive award record anywhere in that scope's actual schema; building it would mean a new table and service method innova-compensation-sn-app's own scope. Rather than pulling that app's team in now, this transaction is out of scope for this Feature (see spec.md). No schema-gate item for it in this pass. - Job Data Changes' storage mechanism is resolved. It writes a new effective-dated
Job Assignmententry carrying the updated description/skill tags, with the prior entry closed viajob_end_dateset to the same effective date — kept for historical record, not overwritten. This is the same insert-new/close-old patternnova-corehcm-sn-app'supdate_sor_nodeflow already uses for department transfers and manager changes (per its ownflow.md), not a new mechanism and not aJob Profileedit. No new field needed on either table. - Post-dated transactions use the platform's Business Event / Event Queue pattern —
not in the transaction-creation skill, confirmed via KB. All six transactions carry
a future effective date (required for Promotion/Demotion/tax withholding; optional
elsewhere), and every one of their source policy docs already has a "Stakeholders by
Phase" section (Confirmed/Reminder/Pre-Execution/Post-Execution/Follow-Up) — these are
literally
x_novaw_platform_event_phase_configuration.phasevalues, not prose. The real mechanism (nova-platform-sn-app'sskills.md/kafka.md): agent callsbuild_events→process_events, immediate phase fires now, later phases queue against theireffective_date, an hourlyBusinessEventOrchestratorjob picks up due events via theNovaEventQueueProcessorextension point (CoreHCMEventQueueProcessoralready implements it), and the Kafka payload'sagent_process_idresumes the LangGraph checkpoint — the same rehydration mechanism already used for approval resume, just triggered by a date arriving instead of a click.nova-corehcm-transaction-creationsays nothing about this (grepped, zero mentions) — it's a second, separate pattern each of the six transactions also needs configured (abusiness_event_configuration+ per-phaseevent_phase_configurationrecords), on top of itstransaction_configuration. Work is configuration withinnova-corehcm-sn-app(extension point already implemented there) — nonova-platform-sn-appcode changes expected. - Test coverage is
nova-corehcm-agent's job, not a separate repo — detailed pattern belongs in a skill, not here. Each of the five transactions needs: a ServiceNow-side eval/integration test, a chat/conversational-experience test, and unit tests for the agent code changes.nova-corehcm-agentalready has an established convention for the first two (tests/EVALS.md,tests/API_integration_tests/INTEGRATION_TESTS.md) — Nova Developer should follow it rather than reinvent test structure; if that convention isn't already captured as a skill, one should be, the same waynova-corehcm-transaction-creationnow captures the SN-script pattern. nova-test-ciis held, not implemented this pass — decided. Its E2E expansion (per Services Affected) is real, needed work, but this Feature does not build it now.test-plan.md's 21 scenarios are what will drive that expansion in a future pass — removed fromdeploy_order/exploration_statusbelow accordingly.
Services Affected¶
| Service | Role |
|---|---|
nova-corehcm-agent |
Extends intent taxonomy and decision routing for the 5 new transaction types; dispatches to nova-corehcm-sn-app for validation, decisioning, and SOR update |
nova-corehcm-sn-app |
New Decision Table configs and ordered context scripts per transaction; new business_event_configuration + per-phase event_phase_configuration records per transaction (Confirmed/Reminder/Pre-Execution/Post-Execution/Follow-Up — CoreHCMEventQueueProcessor extension point already implemented, no new plumbing); schema deltas (reason code, tax jurisdiction); approval task/notification wiring. Job Data Changes needs no new field — resolved to reuse the existing effective-dated Job Assignment insert-new/close-old pattern. |
nova-compensation-sn-app |
Receives the WorkerCompensationService.upsertCompensation() write from Salary Changes, Promotion, and Demotion. (Bonus and Incentive Awards' new-table need is moot — deferred, not built this pass.) |
nova-compensation-agent |
Reflects updated compensation data in existing paycheck/benefits queries once written — read-side only, no new intents expected |
nova-frontend-litjs |
New self-service widget(s) for Worker-facing personal-data fields and a Manager/HRBP approval-queue view, fed by data injected from the ServiceNow host per this repo's consumer-owned data flow pattern |
nova-test-ci is held for this pass — its E2E coverage (corehcm.spec.ts is
currently a generic container-health smoke test only) genuinely needs expanding per
nova-architecture.md's own constraint, but that work is deferred to a future pass
driven by test-plan.md's 21 scenarios, not built now. Removed from deploy_order
below.
Sibling Conflicts / Dependencies¶
No active sibling Feature Set/Feature found in-progress or ready-for-review in this
repo. Two soft dependencies carried from spec.md:
- worker-document-management (separate Feature Set, not yet scoped) — resolved
as a hard dependency, not an open item: Personal Data Updates' dependent/tax-withholding
paths block on it for all document/attachment handling; this Feature builds none of
that capability itself.
- A future Cost Center Change / Org Restructuring / Bonus and Incentive Awards
Feature (same Feature Set) shares the same transaction-framework pattern; no data
dependency.
Risk Flags¶
- TENANT DATA — every new table/field (reason code, tax jurisdiction, incentive
award) must carry
domain/domain_pathperschema/core-hr-schema.md's Domain Separation note; verify each new table follows this before the schema gate. - ACCESS CONTROL —
x_novaw_comp_worker_compensation's write ACL does not includex_novaw_comp.agent. Nova Developer's Phase 1 must confirm the execution script's runtime role includeshr_opsorintegration_writerbefore assuming the cross-scopeWorkerCompensationServicecall will succeed — applies to Salary Changes, Promotion, and Demotion alike. - RCA (Restricted Caller Access) NOT YET GRANTED —
nova-corehcm-sn-apphas two existingsys_scope_privilegerecords, both grantingglobalscope access — zero targetx_novaw_comp.accessibleFrom: 'public'onWorkerCompensationServiceonly makes the target eligible for cross-scope calls — the caller still needs its own outbound RCA record withstatus: allowed. Without one, ServiceNow auto-creates the record asrequested(blocked) the first time Salary Changes/Promotion/Demotion actually runs in a live instance, not at build or deploy time — this would silently fail in testing/production until an admin manually approves it. Required as part of this Feature'snova-corehcm-sn-appchanges: add asys_scope_privilege_<uuid>.xmlrecord to that repo'supdate/directory (pattern from its own existingsys_scope_privilege_0528b550c3a5b290eb7cf3ddd40131de.xml— confirmed by Phase 1 exploration; the.now.tsfluent-SDK pattern this risk originally cited does not apply to this repo, which uses raw XML update sets) —operation: execute,target_name: WorkerCompensationService,target_scope: <x_novaw_comp scope sys_id, resolve from the live instance>,target_type: sys_script_include,status: allowed— pre-declared, not left to auto-request. - NO ISOLABLE HRBP TEST ACCOUNT — per
tests/API_integration_tests/INTEGRATION_TESTS.md§3.2: every account holdingx_novaw_corehcm.hrbpon the test instance also holds fulladmin, so HRBP-gated behavior can't be tested in isolation today. Promotion, Demotion, and Salary Changes all route through HRBP approval — three of five transactions in this pass. A dedicatedhrbp-only test account is needed before this Feature's integration tests can actually verify that gate, not just admin behavior standing in for it.
Schema Gate¶
proposed — no schema-changes.md has been drafted yet for this Feature Set. Phase 1
exploration narrowed what's actually needed, confirmed against the live dictionary XML:
x_novaw_corehcm_job_assignment.reason already exists with promotion/demotion
choice values present — the schema-gate item here is just adding Job Data Changes' own
choice-list values (role refresh / skills update / job architecture alignment), not a
new field. job_assignment.description also already exists (string, max 500) — no
delta needed for Job Data Changes at all. tax_jurisdiction is confirmed not present
anywhere in the person/worker schema — a real, unresolved gate item, but scoped only to
Personal Data Updates' tax-withholding path; address/contact/name are unaffected. Draft
feature-sets/critical-core-hr-transactions/schema-changes.md covering the reason
choice-list addition, the tax-jurisdiction decision, and the new
business_event_configuration/event_phase_configuration records per transaction — the
gate must be signed before SN table/field creation in nova-corehcm-sn-app. No schema
delta is needed in nova-compensation-sn-app this pass (Bonus and Incentive Awards
deferred). The new sys_scope_privilege (RCA) record in nova-corehcm-sn-app is a
security-relevant config change, not a table — call it out explicitly at gate review
even though it isn't a schema delta itself.
Checklist Applicability¶
From github-private/.github/CHECKLIST/feature.md:
- [ ] Unit tests written and passing — applicable (5 repos this pass —
nova-test-ciheld); scenarios sourced fromtest-plan.md - [ ] AI evals (unit level) — applicable (
nova-corehcm-agentgains 5 new intents; utterance-classification coverage viatests/testsets/, per Design Decisions) - [ ] AI evals end-to-end — applicable
- [ ] Feature flags for WIP merged to
main— applicable if rolled out incrementally per transaction - [ ] Backward compatibility confirmed — applicable (SN schema changes in 2 scoped apps)
- [ ] Rollback plan documented — applicable (schema changes are hard to roll back per Risk Flags)
- [ ] Bug bash completed — applicable
- [ ] Accessible via
/novaworkspace interface — applicable if the conversational path is the primary entry - [ ] Portal widgets ready and tested — applicable (
nova-frontend-litjsnew widgets) - [ ] Portal widgets function outside
/nova— applicable, needs explicit test if a standalone portal surface is also supported - [ ] Storybook entries complete — applicable (
nova-frontend-litjs) - [ ] Transactions reviewed and categorized to a pricing tier — applicable, PM/CPO sign-off
- [ ] MAU user counting for new SN actions — applicable
- [ ] Nova User/Admin documentation — applicable
- [ ] Nova Implementation Guide updated — applicable (2 scoped apps + new agent intents)
- [ ]
github-privateengineering info updated — applicable
Open Questions¶
- Does
Workerneed multi-jurisdiction tax-withholding support in v1? (from spec.md) - Confirm the Salary Changes/Promotion/Demotion execution scripts' runtime role
actually has
hr_opsorintegration_writeronx_novaw_comp_worker_compensation(see Risk Flags) —WorkerCompensationService.upsertCompensation()itself is resolved. nova-test-ciis deliberately held this pass (decided) — when a future pass picks it up, doesnova-developer-orchestrator's repo-classification table need a fourth specialized-developer path for it (confirmed today it has none — grepped, zero mentions), or is it handled manually outside the automated pipeline?- Should a second skill (mirroring
nova-corehcm-transaction-creation) document the Business Event / Event Queue phase-configuration pattern before Nova Developer's Phase 1 starts, given it's fully KB-documented but has no skill today the way the transaction-execution layer now does?
For Nova Developer¶
service_repo: nova-corehcm-agent
base_branch: dev
suggested_branch: feature/316-core-hr-transaction-bundle
deploy_order:
- nova-corehcm-sn-app
- nova-compensation-sn-app
- nova-corehcm-agent
- nova-compensation-agent
- nova-frontend-litjs
# nova-test-ci intentionally omitted — held this pass, per decision; a future pass
# adds it back, driven by test-plan.md's 21 scenarios
sn_app_changes_required: true
sn_app_repo: nova-corehcm-sn-app
new_env_vars: []
infra_changes_before_code: none
spec_path: feature-sets/critical-core-hr-transactions/core-hr-transaction-bundle/spec.md
exploration_status:
nova-corehcm-agent: done
nova-corehcm-sn-app: done
nova-compensation-sn-app: done
nova-compensation-agent: done
nova-frontend-litjs: done
Files to Create¶
nova-corehcm-sn-app (raw XML update sets under 3befabcfc38df25044b1bdac0501316d/update/):
- 5×
x_novaw_platform_transaction_configuration_<uuid>.xml— names:personal data update,job data change,promotion,demotion,salary change. Pattern:x_novaw_platform_transaction_configuration_0c9db1a58328cf1067746f60ceaad379.xml("Additional job assignment"). - 8×
x_novaw_platform_context_script_<uuid>.xml—user_information(order 1) for all 5 transactions, plusall_profiles(order 2) for promotion and demotion. Pattern:x_novaw_platform_context_script_7e8aba6ac337b210fc4eba2ed4013178.xml(note: source isactive: false— new records must beactive: true) and "change of job assignment"'sall_profilesscript. - 5×
x_novaw_platform_execution_script_<uuid>.xml— see Implementation Steps for per-transaction service calls. Patterns:..._41cc467183ac0b90cec35fd6feaad30a.xml(update preferred name),..._80bf5b3cc3808710fc4eba2ed4013180.xml(change of job assignment),..._f986ec9083a0471067746f60ceaad36c.xml(contractor to FTE — multi-step reference for promotion/demotion). - 5×
x_novaw_platform_business_event_configuration_<uuid>.xml— one per transaction. Pattern:..._115aa30ec3b50b1078485f73e40131cb.xml("Remove contact"). - 25×
x_novaw_platform_event_phase_configuration_<uuid>.xml— 5 phases (confirmed,reminder,pre_execution,post_execution,follow_up) × 5 transactions. Pattern:..._055aa30ec3b50b1078485f73e40131a7.xml. - 1×
sys_scope_privilege_<uuid>.xml— hard blocker if omitted.operation: execute,source_scope: 3befabcfc38df25044b1bdac0501316d,target_name: WorkerCompensationService,target_scope: <x_novaw_comp scope sys_id — resolve from live instance, do not hardcode>,target_type: sys_script_include,status: allowed. Pattern:sys_scope_privilege_0528b550c3a5b290eb7cf3ddd40131de.xml(existing RCA record in this same repo — NOT thenova-compensation-sn-appfluent.now.tspattern, which doesn't apply here).
nova-corehcm-agent:
tests/testsets/personal_data_updates.yml,job_data_changes.yml,promotion.yml,demotion.yml,salary_changes.yml— pattern:tests/testsets/change_of_department.yml(full standard scenario matrix) /change_of_job_assignment.ymlfor job data changes specifically. Salary Changes' happy path usesmock_scenario: "waiting_for_approval"as primary (no isolablehrbptest account — see Risk Flags).
nova-frontend-litjs:
src/hr-transactions/personal-data-widget.ts+-styles.ts— pattern:src/profile-details/add-contact-modal.ts+employee-details-widget.ts.src/hr-transactions/hr-approval-queue.ts+-styles.ts— pattern:src/superagent-tasks/superagent-tasks.ts.src/hr-transactions/types.ts—HrTransactionTask,PersonalDataPayload,HrTransactionStatus.src/hr-transactions/index.ts— barrel export.src/hr-transactions/__tests__/personal-data-widget.test.ts,hr-approval-queue.test.ts.config/widget-build-config/vite.config.hr-transactions.ts.src/stories/hr-transactions.stories.ts— flagged by explorer as missing from the original high-level plan; needed for the Checklist's Storybook item.
nova-compensation-sn-app, nova-compensation-agent: none — confirmed zero changes needed (see Implementation Steps).
Files to Modify¶
nova-corehcm-agent:tests/testsets/intent_detection.yml(5 new phrasing groups),tests/EVALS.md(5 new testset rows).nova-frontend-litjs:src/index.ts(barrel export),package.jsonbuild script (append new vite build invocation).
Implementation Steps¶
- Transaction configuration records (
nova-corehcm-sn-app) — create the 5transaction_configurationXMLs first; every other record references their sys_ids. - Context scripts —
user_information(order 1) for all 5;all_profiles(order 2) additionally for promotion/demotion (job-profile validation before the level change). - Execution scripts — per-transaction service calls:
- Personal data update →
WorkerService.updatePersonalInfo(userInput, fields). Address/contact/name paths fully buildable now; tax-withholding path blocked on thetax_jurisdictionschema gap (see Open Questions). - Job data change →
DepartmentService.changeDepartment()— insert-new/close-old onJob Assignmentis already built into this call;descriptionfield already exists (string, max 500), no schema delta needed. - Promotion / Demotion →
DepartmentService.changeDepartment()thennew x_novaw_comp.WorkerCompensationService().upsertCompensation({worker_sys_id, effective_date, base_salary}). Set the existingjob_assignment.reasonfield explicitly ("promotion"/"demotion"values already present in its choice list). - Salary change →
upsertCompensation()only, no Core HR–side record change. - Business event + event phase configuration records — one
business_event_configurationper transaction, 5event_phase_configurationchildren each,audience_scriptviaApprovalService.getDownstreamApproverSysIds(). - Cross-scope privilege (RCA) record — create before any live/test execution of Promotion, Demotion, or Salary Change; without it the first execution auto-creates a
requested(blocked) privilege instead of failing loudly. nova-corehcm-agenttest artifacts — 5 new testset YAMLs +intent_detection.yml/EVALS.mdupdates. No graph/node/routing code changes — confirmed the intent taxonomy is entirely SN-config-driven. Coordinate transaction name strings exactly between the SN config names above (personal data update,job data change,promotion,demotion,salary change) and the testset YAMLs'expected_intentfields — a mismatch here would silently break intent detection.nova-frontend-litjswidgets — build both as pure data-receivers (SN host injects props, component only emits events); no direct API calls from inside either widget.
Tests¶
Unit Tests¶
- No new unit tests required in
nova-corehcm-agentornova-compensation-agent— no routing/node code changed; existing suites (tests/unit/test_routing.py, etc.) already cover the unchanged code paths that the 5 new transactions flow through generically. nova-frontend-litjs: Jest +@open-wc/testingfixtures for both new widgets (empty state, data render, event emission on submit/approve/reject) — pattern fromtime-off-page.test.ts.
Eval Cases¶
nova-corehcm-agent: 5 newtests/testsets/*.ymlfiles (standard scenario matrix per transaction) +intent_detection.ymlphrasing cases — see Files to Create above.- No eval files needed in
nova-compensation-agent,nova-compensation-sn-app, ornova-frontend-litjs.