contracts-audit.md
Contracts Audit Log
This file contains user-confirmed acceptable differences between the Go backend and Rescript/TypeScript frontend types that pass through the Yjs CRDT boundary.
IMPORTANT: Only add entries to this file after user consultation and confirmation that the difference is acceptable. This is not a generic log of all findings - it’s a whitelist of known non-issues.
How to Add Entries
When the /contracts command finds a difference that you determine is acceptable:
- Add inline annotation to the source file(s):
// contracts:ignore <brief reason> - Add entry to this log with full context
- Include rationale for why it’s acceptable
Accepted Differences
Type Equivalence: Numeric Types
Difference: Different language-specific names for the same underlying IEEE 754 double precision float
- Go: float32, []float32 (slice)
- TypeScript: number, [number, number] (tuple)
- Rescript: float, (float, float) (tuple)
Files: All waypoint type definitions
- server/waypoint/type.go
- client/src/ffi/waypoint.ts
- client/src/ffi/Waypoint.res
Rationale: These represent the same underlying data type across different language type systems. The Go slice []float32 and TS/Rescript tuples [number, number] / (float, float) both represent a coordinate pair [lon, lat].
Added: 2026-01-15
Type Equivalence: Nullable/Optional Fields
Difference: Language-specific representations of optional/nullable values
- Go: Pointer types or omitempty struct tags
- TypeScript: Union types with | null or | undefined
- Rescript: option<...> variant type
Files: All waypoint type definitions where fields are optional
Rationale: Each language has its own idiomatic way to represent optional values. The semantic meaning is equivalent even though the syntax differs.
Added: 2026-01-15
Intentional Exclusion: type Field
Difference: The type field is present in Go struct but absent from TypeScript/Rescript interfaces
- Go: Type string json:"type" (always “waypoint”)
- TypeScript: Not in WaypointAttributes interface
- Rescript: Not in waypointAttributes type
Files:
- server/waypoint/type.go - includes Type field
- client/src/ffi/waypoint.ts - interface excludes type
- client/src/ffi/Waypoint.res - type excludes type
Rationale: TipTap automatically adds type: "waypoint" as a top-level discriminator field on XmlElement nodes. The Go ygo package uses this field for type switching before extracting attributes. The contract between frontend and backend only covers attributes (id, point, from, label, gid, country, cons), not the discriminator. The type is always “waypoint” and is handled by the framework, not application code.
Added: 2026-05-05
Constraint Structure
Structure: Constraints are arrays of {type: string, value: string} objects
- Go: []Constraint where Constraint{Type ConstraintType, Value string}
- TypeScript: Array<{type: string, value: string}> | null
- Rescript: option<array<Waypoint.Constraint.t>> where Constraint.t = {type_: string, value: string}
Files:
- server/waypoint/type.go - Constraint struct with Type and Value fields
- client/src/ffi/waypoint.ts - Constraint interface
- client/src/ffi/Waypoint.res - Waypoint.Constraint module
Rationale: All constraint values are string-encoded. Integer constraints (MaxSpeed, DailyKMs, Adventure, BreakBeforeDist) are parsed from strings at point of use. This provides a uniform JSON structure across all three languages. Type safety is enforced by the ConstraintType constants in Go rather than the Value type.
Added: 2026-05-05
Future Shared Types
As the system grows, new shared types should be documented here following the same format:
Template for New Entries
### Category: Brief Description
**Difference**: What differs between implementations
- Side A: Description
- Side B: Description
**Files**: List of relevant files
**Rationale**: Why this is acceptable
**Added**: YYYY-MM-DD