Skip to content

MID-11008 Use logical Clock in business/UI-facing timestamp paths#606

Open
kay1313 wants to merge 1 commit intomasterfrom
fix/MID-11008
Open

MID-11008 Use logical Clock in business/UI-facing timestamp paths#606
kay1313 wants to merge 1 commit intomasterfrom
fix/MID-11008

Conversation

@kay1313
Copy link
Copy Markdown
Contributor

@kay1313 kay1313 commented Apr 10, 2026

Summary

This PR improves timestamp consistency across midPoint by introducing and propagating the logical Clock in business- and UI-facing areas, while intentionally preserving real system time in infrastructure, audit, and scheduler-related code.

The goal is to ensure that:

  • user-visible timestamps and business logic respect time overrides (e.g. simulations, testing),
  • while operational, security, and external-facing timestamps remain tied to real wall-clock time.

What was changed

Replaced with Clock (logical time)

Applied logical Clock in:

  • certification workflows (campaigns, cases, stages),
  • notifications and user-visible time computations,
  • workflow/case lifecycle timestamps,
  • reporting and retention logic tied to business-visible data,
  • simulation and role-analysis metadata.
File Replaced Note
AccCertCaseOperationsHelper.java YES RemediedTimestamp is a business-visible certification timestamp in a class that already uses injected Clock, so it should follow logical time override consistently.
AccCertCloserHelper.java YES Campaign cleanup age is certification lifecycle logic, so its threshold should be computed from Clock to stay consistent with logical time override.
AccCertOpenerHelper.java YES This is certification trigger creation based on stage deadlines, so comparing against Clock keeps the trigger logic consistent with overridden logical time.
AccessCertificationStageManagementRun.java YES This class already uses model-beans Clock for stage open/start timestamps, so the pre-deadline trigger check must use the same logical time source to avoid mixed certification timing.
DeadlinePanel.java YES This panel shows user-visible deadline proximity, so “today” must come from Clock instead of the real system date when time override is active.
CampaignProcessingHelper.java YES This string is user-visible certification deadline text (“in/ago/now”), so the comparison baseline must use page.getClock() to match overridden logical time.
CertCampaignListItemDto.java YES This DTO renders user-visible certification deadline text, so it must compute the delta from page.getClock() to stay consistent with time override.
CertCaseOrWorkItemDto.java YES This DTO shows user-visible case/work-item deadline text, so the remaining-time calculation must use page.getClock() instead of real system time.
SimpleCampaignNotifier.java YES Notification timestamps should follow logical time instead of real system time to stay consistent with time overrides.
SimpleCampaignStageNotifier.java YES Notifier shows user-visible stage notification time and deadline countdown, so both values must use Clock to stay consistent with logical time override.
SimpleCaseManagementNotifier.java YES Notifier shows user-visible work-item timing (“in …”, deadline age, notification created on), so those calculations and timestamps should use Clock to stay consistent with logical time override.
SimpleFocalObjectNotifier.java YES Notifier prints a user-visible “notification created on” timestamp, so it should use Clock to reflect midPoint logical time instead of real system time.
SimpleResourceObjectNotifier.java YES Notifier shows a user-visible “notification created on” timestamp, so it should use Clock to reflect logical time override instead of real system time.
SimpleReviewerNotifier.java YES Notification shows a user-visible stage deadline countdown, so it must use Clock instead of system time to stay consistent with logical time override.
SimpleTaskNotifier.java YES Notifier prints a user-visible “notification created on” timestamp, so it should use Clock to follow logical time override instead of real system time.
BasicExpressionFunctions.java YES basic.fromNow() is an expression-level logical-time helper, so it must use Clock as its “now” source to respect time overrides consistently.
WorkItemHelper.java YES The work-item event timestamp becomes part of case/work-item history, so it must follow the same logical time as the rest of the workflow instead of raw system time.
PrimaryChangeProcessor.java YES PrimaryChangeProcessor is the managed owner of workflow dependencies, so passing Clock from here keeps case-start timestamps consistent with logical time without relying on static global access.
StartInstruction.java YES It should be changed because StartInstruction writes persisted case creation metadata, and leaving it on system time would create inconsistent workflow history whenever the rest of the case lifecycle uses Clock.
PcpStartInstruction.java YES Writes a persisted case-creation event into workflow history, so its timestamp should follow the same logical time as the rest of the case lifecycle instead of raw system time.
TaskTypeUtil.java YES Produces user-visible scheduling text like “in”, “retry in”, “now”, and “already passed”, so those calculations should use an explicit logical now from Clock instead of raw system time.
ModelHelper.java YES It is worth changing because the root case name is persisted and user-visible, so its “started at” text should stay consistent with the logical Clock used by the surrounding workflow timestamps.
ActionsExecutedCollectorImpl.java YES This timestamp records executed actions in activity history (not scheduler timing), so using Clock improves consistency, although it remains metadata rather than core business logic.
OperationExecutionWriter.java YES Using Clock here ensures that cleanup decisions are based on the same logical time as the rest of the system, preventing retention inconsistencies when time is overridden.
ReportManagerImpl.java YES Report-output cleanup is retention policy over persisted, user-visible artifacts, so its cutoff time should stay consistent with the system’s logical time instead of raw JVM time.
MiscSchemaUtil.java YES Ensures the retention/cleanup cutoff is computed from the same logical time as the rest of the system, keeping operation history consistent under time overrides instead of mixing in raw system time.
SimulationsGuiUtil.java YES The fallback for missing endTimestamp is part of simulation result display derived from persisted simulation timestamps, so it should use the same logical clock as the simulation context instead of raw wall-clock time.
RoleAnalysisUtils.java YES Ensures all persisted role-analysis timestamps come from a single, controllable logical time source, keeping behavior consistent and testable.

Intentionally NOT replaced (remain on system time)

These areas must use real wall-clock time due to:

  • audit correctness,
  • security guarantees,
  • scheduler/runtime behavior,
  • external protocol requirements.
File Line Replaced Note
SqaleAuditService.java 405 NO Audit retention is operational cleanup against the real audit timeline, not business logic that should follow overridden Clock.
AuditServiceProxy.java 141 NO Using real system time here is correct because audit timestamps must reflect the actual event time, and switching to logical Clock could make audit trails inaccurate or misleading.
AuditedAccessDeniedHandler.java 93 NO Using real system time here is essential because security audit events must record the actual wall-clock moment of access denial, not a potentially overridden logical time.
AuditedLogoutHandler.java 131 NO Using real system time here is appropriate because logout is a security audit event and its timestamp must reflect the actual wall-clock moment, not logical time.
MailMessageTransport.java 355 NO Using real system time here is necessary because email sentDate is external protocol metadata that must reflect actual send time, not overridden logical time.
LegacyMailTransport.java 218 NO This should stay as is because the mail sentDate is external transport metadata that must reflect real wall-clock time, not logical Clock.
TaskQuartzImpl.java 1027 NO This should stay as is because scheduler logic must rely on real system time to ensure correct task execution timing, not logical Clock.
SubscriptionState.java 92|110|191 NO This should stay as is because subscription validity must follow real-world calendar time, not logical or overridden Clock, to ensure correct licensing enforcement.
StalledTasksWatcher.java 78|151 NO This should stay as is because stalled-task detection relies on real elapsed runtime, and using logical/overridden Clock could break watchdog behavior.
TaskCycleExecutor.java 150|191 NO This should stay as is because task execution timestamps are part of scheduler runtime behavior and must use real system time, not logical Clock.
GroupLimitsChecker.java 123|125 NO This should stay as is because retry/rescheduling logic depends on real scheduler time, and using logical Clock could break backoff and fairness behavior.
SecurityHelper.java 84|108 NO This should stay as is because security/audit timestamps must reflect real wall-clock time to preserve accurate and trustworthy audit trails.
MidpointFunctionsImpl.java 2345 NO This should stay as is because trigger optimization relies on real scheduler time for correctness, and using logical Clock could break timing guarantees or safety margins.
WebComponentUtil.java 3616–3620 NO The only callers are progress/runtime DTOs that compute elapsed durations for ongoing processing, this is closer to live runtime display than to business/logical time.
SearchBuilder.java 205 NO The default “today” filter is specifically for searching real audit records, so anchoring it to actual current date is more consistent than using logical Clock, which could make the default audit view drift from the records’ real timestamps.
TimerProgressPanel.java 119 NO In TimerProgressPanel, Instant.now() is driving a live UI elapsed-time counter, so using real wall-clock time is more appropriate than logical Clock, which could make the running timer jump or behave unnaturally under time overrides.
OptimizingTriggerCreatorImpl.java 104 NO This comparison sits in trigger-optimization/safety-margin logic close to scheduler mechanics.
Statistics.java 161 NO This timestamp belongs to operational task-quartz statistics metadata, very close to scheduler/monitoring internals, so it is not strong enough to justify pulling Clock into this area unless explicitly intended.
PageEmailNonce.java 152 NO Keep System.currentTimeMillis() here because nonce expiration is security-critical and must rely on real, non-overridable system time to prevent reuse of expired tokens.

Testing

Added tests covering:

  • certification campaigns
  • stage opening timestamps
  • case remediation timestamps
  • notifications
  • deadline calculations
  • remaining-time rendering

These tests verify that:
logical Clock is respected where expected,
behavior remains consistent under time override.


Result

Consistent logical time in business/UI flows
Preserved correctness for audit, security, scheduler, and external systems
Improved testability and predictability of time-dependent features

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant