Skip to content

Phase 3, Task 8: SensorML Physical System Parser #21

@Sam-Bolling

Description

@Sam-Bolling

Task

Implement a sub-parser for SensorML 3.0 PhysicalSystem and PhysicalComponent descriptors that parses the AbstractPhysicalProcess-level properties (attachedTo, localReferenceFrames, localTimeFrames, position) and the type-specific properties: components/connections for PhysicalSystem, method for PhysicalComponent. This covers both concrete physical process types in one file since they share the AbstractPhysicalProcess base.

ROADMAP Reference: Phase 3, Task 8 — SensorML Physical System Parser (~2-3 hours, Medium-High complexity)


Files to Create or Modify

File Action Est. Lines Purpose
src/ogc-api/csapi/formats/sensorml/physical-system.ts Create ~200-250 PhysicalSystem + PhysicalComponent sub-parser
src/ogc-api/csapi/formats/sensorml/physical-system.spec.ts Create ~150-200 Physical process parser tests

Blueprint Reference

Follow the EDR parser/helper patterns in src/ogc-api/edr/model.ts (126 lines) for function structure and JSDoc style. For test patterns, follow src/ogc-api/edr/model.spec.ts (42 lines). The SimpleProcess sub-parser from Issue #19 and AggregateProcess sub-parser from Issue #20 are sibling sub-parsers — follow their structure for shared AbstractProcess-level parsing.

Scope — What to Implement

Parser Functions

/**
 * Parse a raw SensorML 3.0 PhysicalSystem JSON object into a typed PhysicalSystem.
 *
 * PhysicalSystem is a composite physical system with position, nested
 * components, and data flow connections. Extends AbstractPhysicalProcess.
 *
 * @param json - Raw JSON object with `type: 'PhysicalSystem'`
 * @returns Parsed PhysicalSystem object
 * @throws {SensorMLParseError} If the input is not a valid PhysicalSystem
 * @see https://docs.ogc.org/is/23-000/23-000.html — OGC SensorML 3.0
 */
export function parsePhysicalSystem(json: unknown): PhysicalSystem

/**
 * Parse a raw SensorML 3.0 PhysicalComponent JSON object into a typed PhysicalComponent.
 *
 * PhysicalComponent is a single physical sensor or actuator with position
 * and method description. Extends AbstractPhysicalProcess.
 *
 * @param json - Raw JSON object with `type: 'PhysicalComponent'`
 * @returns Parsed PhysicalComponent object
 * @throws {SensorMLParseError} If the input is not a valid PhysicalComponent
 * @see https://docs.ogc.org/is/23-000/23-000.html — OGC SensorML 3.0
 */
export function parsePhysicalComponent(json: unknown): PhysicalComponent

Inheritance Chain

DescribedObject → AbstractProcess → AbstractPhysicalProcess → PhysicalSystem
                                                             → PhysicalComponent

Both PhysicalSystem and PhysicalComponent share AbstractPhysicalProcess-level properties. Shared parsing logic for both should be factored into a helper function (e.g., parseAbstractPhysicalProcessProps).

AbstractPhysicalProcess Properties (Part 1 L4020)

These properties are unique to the physical process types and must be parsed by this sub-parser:

Property Type Required OGC Spec Description
attachedTo link-2 No Part 1 L4027 Reference to host platform/system this is attached to
localReferenceFrames SpatialFrame[] No Part 1 L4030 Local spatial reference frames attached to the physical component
localTimeFrames TemporalFrame[] No Part 1 L4035 Local temporal reference frames (e.g., "time past mission start")
position Position No Part 1 L4040 Positional information (location and/or orientation)

Position Union Type (Part 1 L4089)

Position is a oneOf with 8 variants (3 deprecated):

Variant Type Description
by Text Text (SWE Common) Textual description of location (building, room)
by Point GeoJSON Point Geographic coordinates (WGS84)
by Pose Pose Full 6DOF position + orientation
by Process AbstractProcess Dynamic position from a process
by Datastream link-2 Link to a datastream providing position
by Location Vector Vector (deprecated) SWE Common Vector
by Position DataRecord DataRecord (deprecated) SWE Common DataRecord
by Trajectory DataArray DataArray (deprecated) SWE Common DataArray

The parser must handle at minimum: Text, Point, Pose, and link-2 variants. Deprecated variants may be handled as passthrough.

Pose Structure (Part 1 L3825)

Pose is a oneOf of 4 variants:

  • GeoPose YPR: { type: 'GeoPose', position: { lat, lon, h }, angles: { yaw, pitch, roll } }
  • GeoPose Quaternion: { type: 'GeoPose', position: { lat, lon, h }, quaternion: { x, y, z, w } }
  • Relative Pose YPR: { type: 'RelativePose', referenceFrame: URI, position: { x, y, z }, angles: { yaw, pitch, roll } }
  • Relative Pose Quaternion: { type: 'RelativePose', referenceFrame: URI, position: { x, y, z }, quaternion: { x, y, z, w } }

SpatialFrame Structure (Part 1 L4048)

{
  label?: string;
  description?: string;
  origin: string;        // Required: textual description of the origin
  axes: Array<{          // Required: axis definitions
    name: string;        // Required
    description: string; // Required
  }>;
}

TemporalFrame Structure (Part 1 L4078)

{
  label?: string;
  description?: string;
  origin: string;  // Required: context of time start
}

PhysicalSystem-Specific Properties (Part 1 L4140)

Property Type Required OGC Spec Description
type 'PhysicalSystem' (const) Yes Part 1 L4148 Type discriminator
components ComponentList No Part 1 L4150 Array of named sub-components
connections ConnectionList No Part 1 L4153 Data flow connections between components

ComponentList and ConnectionList are the same structures as in AggregateProcess (Issue #20). The parser can reuse/import the same component/connection parsing logic.

PhysicalComponent-Specific Properties (Part 1 L4102)

Property Type Required OGC Spec Description
type 'PhysicalComponent' (const) Yes Part 1 L4108 Type discriminator
method ProcessMethod No Part 1 L4110 Algorithm description (same as SimpleProcess)

AbstractProcess-Level Properties

Same inherited properties as Issues #19/#20 (definition, typeOf, configuration, featuresOfInterest, inputs, outputs, parameters, modes). The DescribedObject-level properties may be parsed by shared helpers in the main parser (Issue #22).

Error Handling

  • Throw a descriptive error if type is not 'PhysicalSystem' or 'PhysicalComponent' (depending on which function is called)
  • Throw if position is present but has an unrecognizable variant
  • Throw if localReferenceFrames entries are missing required origin or axes
  • Handle missing optional properties gracefully (return undefined)
  • Handle deprecated Position variants gracefully (passthrough or warning)

JSDoc Requirements

  • Document both parsePhysicalSystem and parsePhysicalComponent with @param, @returns, @throws, @see
  • Add @see links to OGC SensorML 3.0 (23-000) and Part 1 spec line numbers
  • Document helper functions (e.g., parsePosition, parsePose, parseSpatialFrame, parseAbstractPhysicalProcessProps)
  • Explain the Position union type variants in function documentation
  • Follow the JSDoc style in src/ogc-api/edr/model.ts

Testing Requirements

  • Create src/ogc-api/csapi/formats/sensorml/physical-system.spec.ts (~150-200 lines)
  • PhysicalSystem tests:
    • Minimal valid PhysicalSystem (type + required DescribedObject props)
    • With components and connections (reuse patterns from Issue Phase 3, Task 7: SensorML Aggregate Process Parser #20 tests)
    • With position (GeoJSON Point, Pose with YPR, Pose with Quaternion)
    • Component hierarchy parsing (PhysicalSystem containing PhysicalComponents)
  • PhysicalComponent tests:
    • Minimal valid PhysicalComponent
    • With method (ProcessMethod with algorithm and/or description)
    • With position
  • Position parsing tests:
    • Text position (textual location description)
    • GeoJSON Point position
    • GeoPose YPR (lat/lon/h + yaw/pitch/roll)
    • GeoPose Quaternion (lat/lon/h + quaternion)
    • Relative Pose variants
    • Link reference to position datastream
  • SpatialFrame/TemporalFrame tests:
    • Valid SpatialFrame with origin and axes
    • Valid TemporalFrame with origin
    • Missing required fields
  • Invalid document handling: Wrong type, invalid position variant, malformed frames
  • Edge cases: Null position, empty components, unknown properties
  • Follow test patterns from src/ogc-api/edr/model.spec.ts

Scope — What NOT to Touch

Acceptance Criteria

  • src/ogc-api/csapi/formats/sensorml/physical-system.ts exists with both parsePhysicalSystem and parsePhysicalComponent functions
  • Parser handles all AbstractPhysicalProcess-level properties (attachedTo, localReferenceFrames, localTimeFrames, position)
  • Position parsing handles Text, Point, Pose (all 4 variants), link, and deprecated variants
  • SpatialFrame and TemporalFrame parsing validates required fields
  • PhysicalSystem handles components (ComponentList) and connections (ConnectionList)
  • PhysicalComponent handles method (ProcessMethod)
  • Shared AbstractPhysicalProcess parsing logic factored into reusable helper
  • Descriptive errors thrown for invalid documents
  • All new code has complete JSDoc documentation with @see links
  • physical-system.spec.ts exists with tests for both types, position parsing, frame parsing, component hierarchy, and edge cases
  • Existing tests still pass (npm test)
  • No lint errors

Dependencies

Blocked by:

  • Issue Phase 3, Task 5: SensorML Types #18 — SensorML Types (provides PhysicalSystem, PhysicalComponent, Position, Pose, SpatialFrame, TemporalFrame, and related type definitions)
  • Issue Phase 3.4: SWE Common Types #17 — SWE Common Types (provides SWEDataComponent, AnyComponent, Text, Vector, DataRecord, DataArray types used in Position union)

Blocks:


Operational Constraints

⚠️ MANDATORY: Before starting work on this issue, review docs/governance/AI_OPERATIONAL_CONSTRAINTS.md.

Key constraints for this task:

  • Precedence: OGC specifications → AI Collaboration Agreement → This issue description → Existing code → Conversational context
  • No scope expansion: Do not infer unstated requirements or add unrequested features
  • No refactoring: Do not rename, restructure, or "improve" code outside this issue's scope
  • Minimal diffs: Prefer the smallest change that satisfies the acceptance criteria
  • Ask when unclear: If intent is ambiguous, stop and ask for clarification

References

Read these documents before starting implementation. They are ordered by priority.

Primary References (must read)

# Document Section/Lines What It Provides
1 docs/planning/csapi-implementation-guide.md SensorML Handler section (Lines 2990-3050) Full SensorML 3.0 parsing requirements including process types and elements
2 docs/planning/csapi-implementation-guide.md §7 SensorML 3.0 Types (Lines 2657-2790) Code template with PhysicalSystem, PhysicalComponent interfaces and Position/Component structures
3 src/ogc-api/edr/model.ts Full file (126 lines) Blueprint: function structure, JSDoc style
4 src/ogc-api/edr/model.spec.ts Full file (42 lines) Blueprint: test structure, fixture-based testing pattern

Upstream Type/Import References (files this task imports from)

# Document What to Import
1 src/ogc-api/csapi/formats/sensorml/types.ts (Issue #18) PhysicalSystem, PhysicalComponent, Position, Pose, SpatialFrame, TemporalFrame, ComponentList, ConnectionList, ProcessMethod
2 src/ogc-api/csapi/formats/swecommon/types.ts (Issue #17) Text, Vector, DataRecord, DataArray (via import type for Position variants)

Sibling References (same pattern)

# Document What It Provides
1 src/ogc-api/csapi/formats/sensorml/simple-process.ts (Issue #19) Sibling sub-parser — AbstractProcess-level parsing pattern
2 src/ogc-api/csapi/formats/sensorml/aggregate-process.ts (Issue #20) Sibling sub-parser — ComponentList/ConnectionList parsing (reusable for PhysicalSystem)

Research References (context, not required reading)

# Document What It Provides
1 docs/planning/ROADMAP.md (Lines 427-435) Task definition, LOC estimates, test requirements

Specification References (for @see links and field accuracy)

# Document Use
1 OGC SensorML 3.0 (23-000) Canonical SensorML 3.0 data model — primary @see target
2 docs/research/standards/ogcapi-connectedsystems-1.bundled.oas31.yaml PhysicalSystem (L4140), PhysicalComponent (L4102), AbstractPhysicalProcess (L4020), Position (L4089), Pose (L3825), SpatialFrame (L4048), TemporalFrame (L4078), ComponentList (L4112), ConnectionList (L4127)
3 OGC API - Connected Systems Part 1 (23-001) API-level requirements for SensorML encoding
4 OGC GeoPose 1.0 GeoPose standard for Pose structure

Convention Quick Reference

Rule Example
Use .js extension for relative imports import type { PhysicalSystem } from './types.js'
Use import type for interfaces/types import type { PhysicalSystem, Position } from './types.js'
Three-tier hierarchy: import from lower tiers only shared → ogc-api → csapi
Named exports for types and utilities export function parsePhysicalSystem(json: unknown): PhysicalSystem
HTTP mocking: globalThis.fetch = jest.fn() Never use nock, msw, or other libraries
Meaningful tests only Verify parsed position coordinates, component names, not just "runs without throwing"

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions