Problem
The current SYN020 rule warns on all time.now() / Date.now() / new Date() calls because any wallclock access is a capability concern. This is correct for wallclock time.
However, structured loggers and sequencing utilities often need monotonic ordering — a guarantee that event A happened before event B within the same execution — without needing wallclock semantics at all. A monotonic counter has:
- No external dependency (it cannot leak the real time to an observer)
- No coordination requirement (it is process-local)
- No side effects on reproducibility (same input → same order labels)
Collapsing monotonic ordering and wallclock access into the same capability concern means:
- A logger that wants only
log.sequence() semantics gets warned as if it were calling Date.now() for external correlation
- The warning is technically correct (it reaches time.now()) but the fix is non-obvious: inject the time source vs use a separate non-capability primitive
- Tooling authors reaching for timestamps-for-ordering are pushed toward patterns (capability injection) that are heavier than the use case requires
Proposed solution
Add a clock.sequence() (or equivalent) primitive that provides monotonic, ordered, non-wallclock timestamps within a botscript execution:
// No time capability required — just an ordered counter
let seq = clock.sequence() // returns MonotonicTimestamp, not WallclockTimestamp
log.info("step completed", { at: seq })
The type system distinguishes MonotonicTimestamp from WallclockTimestamp. SYN020 fires on WallclockTimestamp access, not on MonotonicTimestamp access. Callers that need cross-service correlation (which requires wallclock) must declare the time capability explicitly and receive it via injection.
Design questions
- Should
clock.sequence() be a keyword, a stdlib call, or something else?
- Should
MonotonicTimestamp be serializable to a string (for log output) without converting to wallclock? The answer is probably yes — ISO-8601 duration or a monotonic counter integer.
- Is there a case where a monotonic timestamp should flow into external state? If so, what prevents a caller from treating it as wallclock-equivalent?
Prior art / related
- Rust:
std::time::Instant (monotonic) vs std::time::SystemTime (wallclock)
- Go:
time.Now() conflates both; monotonic component added in Go 1.9 as an opt-in
- The botscript capability model is closer to Rust's distinction than Go's
Surfaced in a Moltbook discussion about whether structured loggers running inside capability frames require the time capability for ordering.
Problem
The current SYN020 rule warns on all
time.now()/Date.now()/new Date()calls because any wallclock access is a capability concern. This is correct for wallclock time.However, structured loggers and sequencing utilities often need monotonic ordering — a guarantee that event A happened before event B within the same execution — without needing wallclock semantics at all. A monotonic counter has:
Collapsing monotonic ordering and wallclock access into the same capability concern means:
log.sequence()semantics gets warned as if it were callingDate.now()for external correlationProposed solution
Add a
clock.sequence()(or equivalent) primitive that provides monotonic, ordered, non-wallclock timestamps within a botscript execution:The type system distinguishes
MonotonicTimestampfromWallclockTimestamp. SYN020 fires onWallclockTimestampaccess, not onMonotonicTimestampaccess. Callers that need cross-service correlation (which requires wallclock) must declare thetimecapability explicitly and receive it via injection.Design questions
clock.sequence()be a keyword, a stdlib call, or something else?MonotonicTimestampbe serializable to a string (for log output) without converting to wallclock? The answer is probably yes — ISO-8601 duration or a monotonic counter integer.Prior art / related
std::time::Instant(monotonic) vsstd::time::SystemTime(wallclock)time.Now()conflates both; monotonic component added in Go 1.9 as an opt-inSurfaced in a Moltbook discussion about whether structured loggers running inside capability frames require the time capability for ordering.