Skip to content

Commit 0216e6d

Browse files
committed
Replay integration
1 parent afb1043 commit 0216e6d

24 files changed

Lines changed: 4771 additions & 42 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,8 @@ package.json
6262
node_modules/
6363
*.pyc
6464
*.pyo
65+
66+
pre-commit.txt
67+
pre-commit.log
68+
pre-push.txt
69+
pre-push.log

.llm/skills/ci-cd-tooling/wiki-sync.md

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ Fix content in `docs/`, then re-sync.
1515

1616
## Link Format Rules
1717

18-
| Context | Format | Example |
19-
|---------|--------|---------|
20-
| `docs/` files | Lowercase with `.md` | `[Guide](user-guide.md)` |
21-
| `wiki/` files | PascalCase, no extension | `[Guide](User-Guide)` |
22-
| `wiki/_Sidebar.md` | PascalCase, no extension | `[User Guide](User-Guide)` |
23-
| External (non-docs) | Full GitHub URL | `[Code](https://github.com/.../blob/main/src/lib.rs)` |
18+
| Context | Format | Example |
19+
| ------------------- | ------------------------ | ----------------------------------------------------- |
20+
| `docs/` files | Lowercase with `.md` | `[Guide](user-guide.md)` |
21+
| `wiki/` files | PascalCase, no extension | `[Guide](User-Guide)` |
22+
| `wiki/_Sidebar.md` | PascalCase, no extension | `[User Guide](User-Guide)` |
23+
| External (non-docs) | Full GitHub URL | `[Code](https://github.com/.../blob/main/src/lib.rs)` |
2424

2525
Use standard markdown `[Text](Page)` syntax in sidebar -- NOT wiki-link `[[Page|Text]]` syntax (has URL generation bugs).
2626

@@ -57,6 +57,14 @@ docs/*.md --> sync-wiki.py
5757
+-- Add SYNC comment header
5858
+-- Generate _Sidebar.md
5959
--> wiki/*.md
60+
61+
Pre-commit enforcement now runs this sequence for docs/wiki changes:
62+
63+
1. `sync-wiki` regenerates `wiki/*.md` from `docs/`
64+
2. `wiki-consistency` validates links/sidebar/mapping integrity
65+
3. `check-sync-headers` validates reciprocal `<!-- SYNC: ... -->` headers
66+
67+
This prevents committing stale or manually-edited wiki mirrors.
6068
```
6169

6270
## MkDocs Conversion Patterns
@@ -124,26 +132,37 @@ python3 scripts/docs/validate-wiki-output.py # Check rendering issues
124132
3. All wiki pages have sidebar entries
125133
4. No special characters in wiki-link display text
126134

135+
`sync-wiki.py` also validates that every `WIKI_STRUCTURE` page appears in
136+
the generated sidebar and fails fast if any mapped page is missing.
137+
138+
`sync-wiki.py` now enforces deterministic writer normalization for generated
139+
markdown: non-empty outputs end with exactly one LF newline (trailing
140+
whitespace/newlines are normalized). This prevents churn with
141+
`end-of-file-fixer` and keeps repeated sync runs idempotent.
142+
143+
Sidebar coverage validation runs before any wiki writes, so an invalid sidebar
144+
template fails early without leaving partial regenerated output.
145+
127146
### Common Errors
128147

129-
| Error | Fix |
130-
|-------|-----|
148+
| Error | Fix |
149+
| -------------------------------- | ---------------------------- |
131150
| Link points to non-existent page | Add file or fix sidebar link |
132-
| `docs/file.md` not mapped | Add to `WIKI_STRUCTURE` |
133-
| Wiki page has no sidebar entry | Add to `generate_sidebar()` |
134-
| Stale WIKI_STRUCTURE mapping | Remove entry |
151+
| `docs/file.md` not mapped | Add to `WIKI_STRUCTURE` |
152+
| Wiki page has no sidebar entry | Add to `generate_sidebar()` |
153+
| Stale WIKI_STRUCTURE mapping | Remove entry |
135154

136155
## Markdown Link Validation
137156

138157
### Relative Path Resolution
139158

140159
Links resolve from the directory containing the markdown file:
141160

142-
| From | To Root | Example |
143-
|------|---------|---------|
144-
| `docs/` | `../` | `[README](../README.md)` |
145-
| `.github/` | `../` | `[Context](../.llm/context.md)` |
146-
| `.llm/skills/<category>/` | `../../../` | `[README](../../../README.md)` |
161+
| From | To Root | Example |
162+
| ------------------------- | ----------- | ------------------------------- |
163+
| `docs/` | `../` | `[README](../README.md)` |
164+
| `.github/` | `../` | `[Context](../.llm/context.md)` |
165+
| `.llm/skills/<category>/` | `../../../` | `[README](../../../README.md)` |
147166

148167
### Heading Anchor Generation Rules
149168

@@ -153,11 +172,11 @@ Links resolve from the directory containing the markdown file:
153172
4. ` / ` becomes `--`
154173
5. `~` removed
155174

156-
| Heading | Anchor |
157-
|---------|--------|
158-
| `## Quick Start` | `#quick-start` |
175+
| Heading | Anchor |
176+
| ------------------------------------ | ------------------------------ |
177+
| `## Quick Start` | `#quick-start` |
159178
| `## LAN / Local Network (~20ms RTT)` | `#lan--local-network-20ms-rtt` |
160-
| `## Web / WASM Integration` | `#web--wasm-integration` |
179+
| `## Web / WASM Integration` | `#web--wasm-integration` |
161180

162181
### Pipe Escaping in Tables
163182

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ repos:
134134
pass_filenames: false
135135
files: '\.md$'
136136

137+
- id: sync-wiki
138+
name: sync wiki mirrors
139+
entry: python scripts/docs/sync-wiki.py
140+
language: python
141+
pass_filenames: false
142+
files: '^(docs/.*\.md|wiki/.*\.md|scripts/docs/sync-wiki\.py)$'
143+
137144
- id: wiki-consistency
138145
name: wiki consistency check
139146
entry: python scripts/docs/check-wiki-consistency.py

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
1515
## [Unreleased]
1616

17+
### Breaking
18+
19+
- **Breaking:** `FortressEvent::ReplayDesync` — new variant added. Since `FortressEvent` is not `#[non_exhaustive]`, exhaustive matches must now handle this variant.
20+
21+
### Added
22+
23+
- `ReplaySession::new_with_validation()` constructor that enables checksum validation mode, emitting `SaveGameState` requests and comparing checksums against the replay recording
24+
- `ReplaySession::is_validating()` accessor to check if checksum validation mode is enabled
25+
- `SessionBuilder::start_replay_session_with_validation()` builder method for creating a validation-enabled replay session
26+
- `SessionTelemetry` trait for observing session performance events (rollbacks, prediction misses, frame advances, network stats)
27+
- `CollectingTelemetry` test helper that accumulates `TelemetryEvent` values for assertions
28+
- `TelemetryEvent` enum with `Rollback`, `PredictionMiss`, `NetworkStatsUpdate`, and `FrameAdvance` variants
29+
- `SessionBuilder::with_telemetry()` to attach a telemetry observer to P2P sessions
30+
- `Replay<I>` type for recorded match data with `to_bytes()` / `from_bytes()` serialization using deterministic bincode codec
31+
- `ReplayMetadata` type containing library version, player count, and total frame count
32+
- `ReplaySession<T>` session type implementing `Session<T>` for deterministic replay playback
33+
- `SessionBuilder::with_recording(bool)` to enable input recording during P2P sessions
34+
- `SessionBuilder::start_replay_session(replay)` to create a replay playback session
35+
- `P2PSession::is_recording()` to check if replay recording is active
36+
- `P2PSession::into_replay()` to extract the recorded `Replay` after a session ends (consumes the session)
37+
- `P2PSession::take_replay()` to extract the recorded `Replay` without consuming the session (recording stops after extraction)
38+
- `Replay::validate()` to verify internal consistency of replay data
39+
- Re-exports `Replay`, `ReplayMetadata`, and `ReplaySession` in prelude
40+
41+
### Changed
42+
43+
- `P2PSession` now captures actual game state checksums during replay recording (previously always recorded `None`)
44+
1745
## [0.7.0]
1846

1947
### Added

0 commit comments

Comments
 (0)