115 lines
3.9 KiB
Markdown
115 lines
3.9 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: TidalProvider implementation
|
|
|
|
The system SHALL provide `TidalProvider` implementations for Earth (TICON, ADMIRALTY) and any planet (physics-based).
|
|
|
|
#### Scenario: Provider creation
|
|
|
|
- **WHEN** `createTiconProvider()`, `createAdmiraltyProvider(options)`, and `createPhysicsBasedProvider()` are called
|
|
- **THEN** each returns an object satisfying `TidalProvider`
|
|
|
|
### Requirement: Earth harmonic providers preserved
|
|
|
|
The system SHALL preserve TICON and ADMIRALTY provider logic, harmonic constituent engine, and station data.
|
|
|
|
#### Scenario: TICON prediction
|
|
|
|
- **WHEN** `predictHeight` is called via a TICON provider for a known UK station at a known time
|
|
- **THEN** the result matches the legacy `@suaveplan/tides` value within `0.01` metres
|
|
|
|
### Requirement: Multi-satellite physics model
|
|
|
|
The system SHALL compute tidal height from all satellites in `PlanetConfig` using superposition.
|
|
|
|
#### Scenario: Two-satellite planet
|
|
|
|
- **WHEN** a `PlanetConfig` with two satellites is used with `createPhysicsBasedProvider()`
|
|
- **AND** `predictHeight` is called
|
|
- **THEN** the result reflects the combined gravitational influence
|
|
|
|
### Requirement: Individual satellite contribution
|
|
|
|
The system SHALL export `satelliteTidalContribution` for visualising per-satellite effects.
|
|
|
|
#### Scenario: Single contribution
|
|
|
|
- **WHEN** `satelliteTidalContribution(planet, satellite, coord, time)` is called
|
|
- **THEN** the result is a number representing that satellite's height contribution
|
|
|
|
### Requirement: Zod schemas for all public options
|
|
|
|
The system SHALL validate all public option types with Zod and throw `ValidationError` on failure.
|
|
|
|
#### Scenario: Invalid options
|
|
|
|
- **WHEN** `createAdmiraltyProvider({ apiKey: "" })` is called with an invalid key
|
|
- **THEN** validation throws before any network request
|
|
|
|
### Requirement: AbortSignal on async methods
|
|
|
|
The system SHALL accept `AbortSignal` on every async provider method.
|
|
|
|
#### Scenario: Abort tide prediction
|
|
|
|
- **WHEN** `predictHeight` is called with an aborted signal
|
|
- **THEN** the promise rejects with an abort error
|
|
|
|
### Requirement: TidesError with stable codes
|
|
|
|
The system SHALL export `TidesError` extending `@suaveplan/error` with `TIDES.*` error codes.
|
|
|
|
#### Scenario: Error code stability
|
|
|
|
- **WHEN** a provider throws for a missing station
|
|
- **THEN** the error code begins with `TIDES.`
|
|
- **AND** the same condition yields the same code across calls
|
|
|
|
### Requirement: OTel instrumentation
|
|
|
|
The system SHALL create OTel spans, counters, and histograms on every provider call.
|
|
|
|
#### Scenario: Span creation
|
|
|
|
- **WHEN** `predictHeight` is called
|
|
- **THEN** an OTel span is started with the operation name
|
|
- **AND** a histogram records the prediction latency
|
|
|
|
### Requirement: Injectable fetch and clock
|
|
|
|
The system SHALL accept `fetchFn`, `clockFn`, and optional `cacheFn` in ADMIRALTY provider options.
|
|
|
|
#### Scenario: Custom fetch
|
|
|
|
- **WHEN** a custom `fetchFn` is injected into `createAdmiraltyProvider`
|
|
- **THEN** the provider uses it for all HTTP requests
|
|
|
|
### Requirement: Property-based tests on harmonic engine
|
|
|
|
The system SHALL include fast-check property tests on the harmonic prediction engine.
|
|
|
|
#### Scenario: Property test existence
|
|
|
|
- **WHEN** the test suite runs
|
|
- **THEN** fast-check properties verify monotonicity and bounds of the harmonic sum
|
|
|
|
### Requirement: TidalProvider routing
|
|
|
|
The system SHALL export `TidalProviderImpl` routing Earth to `earthProviders` and non-Earth to `physicsProvider`.
|
|
|
|
#### Scenario: Earth vs Mars routing
|
|
|
|
- **WHEN** `predictHeight` is called with `EARTH`
|
|
- **THEN** the first Earth provider is tried
|
|
- **AND** when called with a Mars-like config, the physics provider is used
|
|
|
|
### Requirement: Planet identification by name
|
|
|
|
The system SHALL identify Earth by `planet.name.toLowerCase() === "earth"`.
|
|
|
|
#### Scenario: Name-based routing
|
|
|
|
- **WHEN** a planet with `name: "Earth"` is passed
|
|
- **THEN** it routes to Earth providers
|
|
- **AND** a planet with `name: "Mars"` routes to physics
|