Skip to content

fix(tsa): keep stamping through a grace window after the last good sync - #357

Merged
Bugs5382 merged 1 commit into
mainfrom
fix/356-tsa-grace-window
Oct 7, 2026
Merged

Bugs5382 merged 1 commit into
mainfrom
fix/356-tsa-grace-window

Conversation

@Bugs5382

@Bugs5382 Bugs5382 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

What and why

The TSA clock gate refused every request as soon as one time-sync poll went unanswered, because it looked only at the latest round. A single lost NTP packet took the TSA down until the next good poll.

The gate now trusts the clock for a grace window after the last good sync and refuses with timeNotAvailable only when one of these limits is hit:

Limit Refused when Default
no_good_sync no good sync this boot (also a node with no time source)
adjustment_refused the servers answered but the clock was not adjusted (sources disagree, step refused); cleared by the next good sync
max_sync_age the last good sync is older than pki.tsa.max_sync_age_seconds 3600, at most 86400
max_clock_error the offset at the last good sync plus max_drift_ppm of the time since exceeds max_clock_error_ms accuracy_ms (1s)
  • max_drift_ppm defaults to 100, at most 500 (the NTP frequency tolerance).
  • max_clock_error_ms larger than the effective accuracy_ms is rejected by config validation, so a token never claims more accuracy than the clock is trusted to have.
  • New proto fields: Tsa.max_sync_age_seconds (8), max_drift_ppm (9), max_clock_error_ms (10) and TimeSyncStatus.adjustment_refused (10). The time-sync engine sets adjustment_refused on answered-but-unapplied rounds and clears it on the next good sync.
  • The rejection's statusString names the limit and its value, for example the TSA time source is not available: max_sync_age=1h0m0s exceeded (1h12m3s). Server names and sync errors stay in the node log.
  • docs/tsa.md documents the limits, defaults and the accuracy rule. The website companion PR covers the public docs.

Testing

  • task ci passes locally (fmt, proto lint, generate verify, lint, vet, test, build).
  • Table tests for the gate (window edges, drift crossing the bound, negative offsets, refused rounds, never synced), the error estimate, the responder statusString, config defaults, validation and the proto round trip.

Closes #356

The clock gate refused every request as soon as one time-sync poll went
unanswered. It now trusts the clock while the last good sync is younger
than pki.tsa.max_sync_age_seconds (default 3600) and the estimated clock
error, the offset at that sync plus max_drift_ppm (default 100) of the
time since, stays within max_clock_error_ms (default accuracy_ms). A
round the servers answered but that was not applied sets the new
TimeSyncStatus.adjustment_refused flag, which still refuses until the
next good sync. Config with max_clock_error_ms above the accuracy is
rejected. The timeNotAvailable status string names the limit and value.

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
@github-actions github-actions Bot added the fix Bug fix (fix). Patch. label Oct 7, 2026
@Bugs5382 Bugs5382 self-assigned this Oct 7, 2026
@Bugs5382
Bugs5382 merged commit e05480d into main Oct 7, 2026
15 checks passed
@Bugs5382
Bugs5382 deleted the fix/356-tsa-grace-window branch October 7, 2026 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug fix (fix). Patch.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(tsa): refuse stamping on clock age or error bound, not on one failed poll

1 participant