# Wall-time clocks (Accrues = false)

> A timer that measures REAL time instead of SLA time. Written as a block on any clock-declaring setting — `Expire`, `Deadline`, a milestone's `Within`, a `Remind` cadence — `Accrues = false` exempts that one clock from BOTH SLA gates: the run's service-hours schedule and the per-state accrual pause. It is what lets an auto-close fire in a state that carries no service promise.

<!-- id: workflow-wall-time-clock · area: workflow · stability: stable · html: https://osysharp.com/reference/workflow/wall-time-clock/ -->

## Summary        {#summary}
A workflow clock measures **SLA time** by default: it advances only inside the run's `ServiceHours` windows, and only
while the run sits in a state named by `Accrues`. That is right for a promise ("first response within 4 hours") and
wrong for an operational timer ("close it 7 days after it was resolved") — seven days there means seven **real** days,
and the state a resolved ticket sits in accrues no promise at all.

`Accrues = false` says which kind a clock is, in the declaration itself.

## Signature      {#signature}
```osy syntax
// the scalar form is unchanged and means SLA ticks
Expire = TimeSpan.FromHours(4);

// the block form states the gate
Expire   { Within = TimeSpan.FromDays(7);  Accrues = false; }
Deadline { Within = TimeSpan.FromDays(30); Accrues = false; }

Assigned {
  Within  = TimeSpan.FromHours(2);
  Accrues = false;                                    // a real-time nudge, not a service promise
  Remind Ping(After = TimeSpan.FromMinutes(10), ThenEvery = TimeSpan.FromMinutes(10), Accrues = false) { … }
}
```

## Description    {#description}
`Accrues = false` exempts one clock from **both** SLA gates:

- **The service-hours schedule.** A wall-time clock walks real time, so a 7-day budget lands 7×24 hours later
  regardless of nights, weekends or holidays. Re-pointing the run at a different schedule mid-flight does not
  retroactively change what its remaining budget means.
- **The per-state accrual pause.** A state outside the workflow's `Accrues` list pauses every SLA clock on the run.
  A wall-time clock keeps running through it.

That second exemption is the point. **An ordinary `Expire` in a state outside `Accrues` cannot fire at all** — the
accrual pause runs on the very state-entry that armed the timer, so the clock is suspended before it is ever swept.
The compiler refuses that shape and names the two ways out:

```text
state 'Resolved' declares an `Expire` but is not in this workflow's `Accrues` list, so its SLA clock is paused the
moment the run enters the state and the timer can never fire. If this is a wall-time timer (an auto-close, a cadence),
say so: `Expire { Within = <time>; Accrues = false; }`. If it is an SLA promise, add the state to `Accrues`.
```

**It is declared, never inferred.** A state moving in or out of `Accrues` is a change to what the run *promises*; it
must not also, silently, change what an existing timer *measures*. So the gate is written on the clock, and a clock
that says nothing is an SLA clock — the reading it has always had.

**Every clock-declaring setting takes it**, and they mean the same thing everywhere: the workflow-level `Expire` and
`Deadline`, a per-state `Expire`, a milestone's `Within`, and a `Remind` cadence. A per-state `Expire` overrides the
workflow-level one **together with its gate** — the flag travels with whichever budget won, so an inherited default
never picks up a state's flag.

## Examples       {#examples}
One support flow carrying both kinds of clock. `Working` accrues the promise, so its `Expire` and its milestone
`Within` are SLA time. `Resolved` accrues nothing — the promise is already met — yet still auto-closes after seven
**real** days, and the nudge cadence is in real minutes even though the milestone it hangs off is a service promise:

```osy title="SLA clocks and wall-time clocks side by side" test app=wf-wall-time-clock
enum TicketStatus { Working, Resolved, Closed, Escalated }

entity Ticket {
  [Required, MaxLength(200)] string Title;
  TicketStatus Status = TicketStatus.Working;
}

workflow SupportTicket {
  Tracks    = Ticket.Status;
  Autostart = false;
  Initial   = Working;
  Accrues   = [Working];                   // Resolved is deliberately NOT here

  event Resolve();
  event Review();

  state Working {
    Expire = TimeSpan.FromHours(4);        // an SLA clock: service hours, paused whenever the run parks
    on Expire { goto Escalated; }

    subscribe Review() as Reviewer {
      Assigned {
        Within = TimeSpan.FromHours(4);    // 4 SERVICE hours to pick it up…
        Remind Ping(After = TimeSpan.FromMinutes(10), ThenEvery = TimeSpan.FromMinutes(10), Accrues = false) {
          Log.Information("still unassigned");   // …nudged every 10 REAL minutes
        }
        Unassigned { goto Escalated; }
      }
    }

    subscribe Resolve();
    on Resolve { goto Resolved; }
  }

  state Resolved {
    Expire { Within = TimeSpan.FromDays(7); Accrues = false; }   // seven REAL days
    on Expire { goto Closed; }
  }

  terminal success Closed    { }
  terminal error   Escalated { Message = "escalated"; }
}
```

Drop the `Accrues = false` from `Resolved` and the app stops compiling — that timer could never have fired.

## See also       {#see-also}
- [ServiceHours (SLA-accrual windows)](https://osysharp.com/reference/workflow/service-hours/) — the schedule an SLA clock accrues within, and which a wall-time clock ignores
- [Assigned / Finished (milestones)](https://osysharp.com/reference/workflow/milestone/) — `Within`, the SLA a slot must be reached inside
- [Remind (milestone reminders)](https://osysharp.com/reference/workflow/remind/) — the reminder whose cadence this most often applies to
