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:

  1. Add inline annotation to the source file(s): // contracts:ignore <brief reason>
  2. Add entry to this log with full context
  3. 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