Skip to content

Commit 0b7fd6b

Browse files
authored
Merge pull request #51 from dexcompiler/copilot/scaffold-vitepress-docs
Scaffold VitePress 1.x documentation site with GitHub Pages CI/CD
2 parents e2232f0 + b10561c commit 0b7fd6b

23 files changed

Lines changed: 3606 additions & 0 deletions

.github/workflows/docs.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Docs
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
pages: write
13+
id-token: write
14+
15+
concurrency:
16+
group: pages
17+
cancel-in-progress: false
18+
19+
jobs:
20+
build:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Pages
27+
uses: actions/configure-pages@v5
28+
29+
- name: Setup Node
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: 20
33+
cache: npm
34+
cache-dependency-path: docs/package-lock.json
35+
36+
- name: Install docs dependencies
37+
working-directory: docs
38+
run: npm ci
39+
40+
- name: Prepare logo asset
41+
run: cp assets/clockworks-display-resized.png docs/public/logo.png
42+
43+
- name: Build VitePress site
44+
working-directory: docs
45+
run: npm run docs:build
46+
47+
- name: Upload Pages artifact
48+
uses: actions/upload-pages-artifact@v3
49+
with:
50+
path: docs/.vitepress/dist
51+
52+
deploy:
53+
needs: build
54+
if: github.ref == 'refs/heads/main'
55+
runs-on: ubuntu-latest
56+
environment:
57+
name: github-pages
58+
url: ${{ steps.deployment.outputs.page_url }}
59+
steps:
60+
- name: Deploy to GitHub Pages
61+
id: deployment
62+
uses: actions/deploy-pages@v4
63+

docs/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
.vitepress/dist/
3+
.vitepress/cache/
4+
public/logo.png

docs/.vitepress/config.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { defineConfig } from 'vitepress'
2+
3+
export default defineConfig({
4+
base: '/Clockworks/',
5+
title: 'Clockworks',
6+
description: 'Deterministic, fully controllable time for distributed-system simulations and testing.',
7+
8+
head: [
9+
['meta', { property: 'og:title', content: 'Clockworks' }],
10+
['meta', { property: 'og:description', content: 'Deterministic, fully controllable time for distributed-system simulations and testing.' }],
11+
['meta', { property: 'og:type', content: 'website' }],
12+
],
13+
14+
lastUpdated: true,
15+
16+
markdown: {
17+
theme: { light: 'github-light', dark: 'github-dark' },
18+
lineNumbers: true,
19+
},
20+
21+
themeConfig: {
22+
// Absolute paths are resolved relative to `base`
23+
logo: '/logo.png',
24+
siteTitle: 'Clockworks',
25+
26+
nav: [
27+
{ text: 'Guide', link: '/guide/' },
28+
{ text: 'Concepts', link: '/concepts/why-clockworks' },
29+
{
30+
text: 'API Reference',
31+
link: 'https://www.nuget.org/packages/Clockworks',
32+
target: '_blank',
33+
},
34+
{ text: 'Changelog', link: '/changelog' },
35+
{
36+
text: 'v1.3.0',
37+
link: 'https://github.com/dexcompiler/Clockworks/releases',
38+
target: '_blank',
39+
},
40+
],
41+
42+
sidebar: {
43+
'/guide/': [
44+
{
45+
text: 'Guide',
46+
items: [
47+
{ text: 'Getting Started', link: '/guide/' },
48+
{ text: 'Installation', link: '/guide/#installation' },
49+
{ text: 'Simulated Time', link: '/guide/simulated-time' },
50+
{ text: 'Timeouts', link: '/guide/timeouts' },
51+
{ text: 'UUIDv7 Generation', link: '/guide/uuidv7' },
52+
{ text: 'Hybrid Logical Clock', link: '/guide/hlc' },
53+
{ text: 'Vector Clock', link: '/guide/vector-clock' },
54+
{ text: 'Instrumentation', link: '/guide/instrumentation' },
55+
],
56+
},
57+
],
58+
'/concepts/': [
59+
{
60+
text: 'Concepts',
61+
items: [
62+
{ text: 'Why Clockworks?', link: '/concepts/why-clockworks' },
63+
{ text: 'HLC vs Vector Clocks', link: '/concepts/hlc-vs-vector' },
64+
{ text: 'Determinism Model', link: '/concepts/determinism' },
65+
{ text: 'Security Considerations', link: '/concepts/security' },
66+
],
67+
},
68+
],
69+
},
70+
71+
socialLinks: [
72+
{ icon: 'github', link: 'https://github.com/dexcompiler/Clockworks' },
73+
],
74+
75+
footer: {
76+
message: 'Released under the MIT License.',
77+
copyright: 'Copyright © 2024–present Dexter Ajoku (CloudyBox)',
78+
},
79+
80+
search: {
81+
provider: 'local',
82+
},
83+
84+
editLink: {
85+
pattern: 'https://github.com/dexcompiler/Clockworks/edit/main/docs/:path',
86+
text: 'Edit this page on GitHub',
87+
},
88+
},
89+
})

docs/.vitepress/theme/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import DefaultTheme from 'vitepress/theme'
2+
export default DefaultTheme

docs/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: Docs README
3+
---
4+
5+
# Documentation site (VitePress)
6+
7+
This directory contains the Clockworks documentation site, built with VitePress 1.x.
8+
9+
## Local development
10+
11+
1) Install dependencies:
12+
13+
```bash
14+
cd docs
15+
npm install
16+
```
17+
18+
2) Copy the logo into `docs/public/`:
19+
20+
```bash
21+
cp ../assets/clockworks-display-resized.png public/logo.png
22+
```
23+
24+
3) Start the dev server:
25+
26+
```bash
27+
npm run docs:dev
28+
```
29+
30+
## Notes on GitHub Pages
31+
32+
The site is deployed as a GitHub Pages **project site** under `/Clockworks/`, so the VitePress `base` is set to:
33+
34+
- `base: '/Clockworks/'`
35+
36+
In CI, the workflow copies `assets/clockworks-display-resized.png` to `docs/public/logo.png` before running the build. The generated `logo.png` is intentionally excluded from git.
37+

docs/changelog.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Changelog
3+
---
4+
5+
# Changelog
6+
7+
This page mirrors the repository root `CHANGELOG.md`.
8+
9+
<!-- NOTE: kept in sync manually with /CHANGELOG.md -->
10+
11+
## [Unreleased]
12+
13+
## [1.3.0] - 2026-02-19
14+
15+
### Fixed
16+
- Fix packed HLC decode for high-bit wall times.
17+
- Enforce HLC drift bounds when the clock moves backwards.
18+
- Harden `VectorClock` string parsing and coordinator locking.
19+
- Fix `VectorClock` overflow behavior.
20+
- Fix thread safety in demo `FailureInjector`.
21+
- Preserve correlation IDs correctly in at-least-once demo flows.
22+
- Prevent a template dictionary memory leak in the integration demo.
23+
- Stabilize demo `MessageId` generation.
24+
25+
### Changed
26+
- Optimize HLC timestamp serialization/parsing, and simplify witness max selection.
27+
- Make HLC message header `TryParse` non-exceptional.
28+
- Split HLC coordinator supporting types into separate files.
29+
- Optimize `VectorClock` merge/compare/increment and serialization.
30+
- Use `ArrayPool<T>` for vector clock merge buffers.
31+
- Use `CollectionsMarshal` for vector clock canonicalization.
32+
- UUIDv7 packing now uses `BinaryPrimitives` and a tighter packing path.
33+
- UUIDv7 factory batch generation throughput improvements.
34+
- Adopt C# 14 extension member blocks.
35+
36+
### Added
37+
- Add high-value property tests for HLC and vector clocks.
38+
- Demo: add distributed-systems at-least-once simulation with HLC/VC stats.
39+
40+
### Documentation
41+
- Update README with HLC and `VectorClock` wire formats.
42+
- Clarify HLC drift bounds and ordering scope.
43+
44+
### Build
45+
- Infrastructure scripts: improve setup/maintenance harness and dotnet installation step.
46+
47+
## [1.2.0] - 2026-01-27
48+
49+
### Changed
50+
- HLC receive semantics now witness the full remote `HlcTimestamp` `(wallTime, counter, nodeId)` (including nodeId tie-breaking) rather than only the remote wall time.
51+
- HLC coordinator receive statistics now treat "remote ahead" based on full timestamp ordering.
52+
53+
### Added
54+
- Additional property tests for `HlcCoordinator` covering remote-ahead by counter, nodeId tie-breaking, remote-behind behavior, and mixed send/receive/time interleavings.
55+
- Unit test coverage for receiving a remote timestamp with higher counter at the same wall time.
56+
57+
### Build
58+
- Centralized common build properties in `Directory.Build.props`.
59+

docs/concepts/determinism.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: Determinism Model
3+
---
4+
5+
# Determinism Model
6+
7+
Clockworks is designed so **simulated scheduler time deterministically drives timers/timeouts**, while **wall time can be manipulated independently** to model clock skew, rewinds, and other wall-clock effects.
8+
9+
## Two notions of time
10+
11+
When using `SimulatedTimeProvider`, there are two separate “clocks”:
12+
13+
- **Wall time** (`GetUtcNow()`): controllable, may move backwards via `SetUtcNow(...)`.
14+
- **Scheduler time** (timers + `GetTimestamp()`): monotonic, advances only via `Advance(...)`.
15+
16+
This split is intentional:
17+
18+
- Timers/timeouts are driven by scheduler time so they’re reproducible and ordered deterministically.
19+
- Wall time remains available for scenarios where you want to simulate clock drift, skew, or rewinds without changing timer ordering.
20+
21+
## Deterministic timer behavior
22+
23+
Timers created via `SimulatedTimeProvider.CreateTimer(...)` fire when scheduler time reaches their due time. Advancing time:
24+
25+
```csharp
26+
var tp = new SimulatedTimeProvider();
27+
var fired = 0;
28+
29+
using var timer = tp.CreateTimer(_ => fired++, null, TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan);
30+
31+
tp.Advance(TimeSpan.FromSeconds(1));
32+
// fired == 1
33+
```
34+
35+
Periodic timers default to **coalescing** on large time jumps: if you advance by a long duration, the timer is rescheduled from “now” (rather than firing repeatedly for every missed period). This keeps simulations fast and avoids unbounded callback loops.
36+
37+
## Timeout determinism
38+
39+
`Timeouts.CreateTimeout(...)` and `Timeouts.CreateTimeoutHandle(...)` schedule cancellation using the provided `TimeProvider`. If that provider is simulated, timeouts are fast-forwardable and fully deterministic.
40+

docs/concepts/hlc-vs-vector.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
title: HLC vs Vector Clocks
3+
---
4+
5+
# HLC vs Vector Clocks
6+
7+
Clockworks provides two complementary approaches for tracking ordering/causality in distributed systems and simulations:
8+
9+
- **Hybrid Logical Clock (HLC)**: a *total order* that stays close to physical time with \(O(1)\) metadata.
10+
- **Vector Clock (VC)**: a *partial order* with exact causality and *concurrency detection*.
11+
12+
## Hybrid Logical Clock (HLC)
13+
14+
HLC timestamps combine a wall-clock time with a logical counter (and node ID tie-breaking). In Clockworks, drift bounds are configurable via `HlcOptions.MaxDriftMs`, and strict enforcement can be enabled with `ThrowOnExcessiveDrift`.
15+
16+
Best for:
17+
18+
- Systems where wall-clock proximity matters (time-based SLAs, time-window queries)
19+
- High-throughput paths where \(O(1)\) overhead is critical
20+
- “Good enough” ordering when you don’t need to detect concurrency
21+
22+
Trade-offs:
23+
24+
-\(O(1)\) space/time overhead per event
25+
- ✅ Close to physical time; bounded drift enforcement is configurable
26+
- ❌ Cannot detect concurrency (only ordering)
27+
- ❌ Benefits from reasonably synchronized clocks
28+
29+
## Vector Clock (VC)
30+
31+
Vector clocks track a counter per node. They can prove that one event happened-before another, and can also detect concurrency.
32+
33+
Best for:
34+
35+
- Exact happens-before relationships
36+
- Conflict/concurrency detection in replicated state
37+
- Debugging distributed races (seeing where concurrency occurred)
38+
- Scenarios where relying on physical time is undesirable
39+
40+
Trade-offs:
41+
42+
- ✅ Exact causality
43+
- ✅ Detects concurrency
44+
- ✅ No dependency on physical time
45+
- ❌ Metadata grows with number of nodes
46+
- ❌ Merge/compare costs scale with entries present in the clock
47+
48+
## Practical guidance
49+
50+
- Prefer **HLC** if you primarily want a cheap, monotonic ordering that correlates with wall time.
51+
- Prefer **Vector Clocks** when concurrency detection is important (e.g., last-writer-wins vs merge, replicated workflows, debugging).
52+
- In simulations, you can use both:
53+
- HLC for cheap global ordering / time-ordered IDs
54+
- Vector clocks for precise causality assertions
55+

docs/concepts/security.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Security Considerations
3+
---
4+
5+
# Security Considerations
6+
7+
Clockworks focuses on deterministic time and causality tooling. As with any identifiers and timestamps that cross trust boundaries, be deliberate about what you expose.
8+
9+
## UUIDv7 time exposure
10+
11+
UUIDv7 values embed a millisecond-resolution timestamp by design (RFC 9562). As a result, UUIDv7 generated by `UuidV7Factory` can often be decoded to reveal an approximate creation time, and ordering/rate information can sometimes be inferred from sequences of IDs.
12+
13+
If you are issuing identifiers across **untrusted/public boundaries** (URLs, externally-visible resource IDs, third-party logs), do not treat UUIDv7 as opaque.
14+
15+
Common mitigations:
16+
17+
- Use a random UUID (UUIDv4) for externally-visible identifiers.
18+
- Keep UUIDv7 as an internal primary key, and expose a separate opaque token externally.
19+
- Wrap/encrypt identifiers for external presentation if you need internal ordering but external opacity.
20+

0 commit comments

Comments
 (0)