Skip to content

Phase 3, Task 7: SensorML Aggregate Process Parser #20

@Sam-Bolling

Description

@Sam-Bolling

Task

Implement a sub-parser for SensorML 3.0 AggregateProcess descriptors that parses the AbstractProcess-level properties and the AggregateProcess-specific components (ComponentList) and connections (ConnectionList) properties, handling recursive component parsing and data flow connection mapping.

ROADMAP Reference: Phase 3, Task 7 — SensorML Aggregate Process Parser (~2-3 hours, Medium-High complexity)


Files to Create or Modify

File Action Est. Lines Purpose
src/ogc-api/csapi/formats/sensorml/aggregate-process.ts Create ~200-250 AggregateProcess sub-parser
src/ogc-api/csapi/formats/sensorml/aggregate-process.spec.ts Create ~150-200 AggregateProcess 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 (simple-process.ts) is the closest sibling — follow its structure for shared AbstractProcess-level parsing, then add component/connection handling.

Scope — What to Implement

Parser Function

/**
 * Parse a raw SensorML 3.0 AggregateProcess JSON object into a typed AggregateProcess.
 *
 * AggregateProcess is a composite non-physical process that orchestrates
 * sub-processes via named components and data flow connections.
 *
 * @param json - Raw JSON object with `type: 'AggregateProcess'`
 * @returns Parsed AggregateProcess object
 * @throws {SensorMLParseError} If the input is not a valid AggregateProcess
 * @see https://docs.ogc.org/is/23-000/23-000.html — OGC SensorML 3.0
 */
export function parseAggregateProcess(json: unknown): AggregateProcess

Properties to Parse

From AbstractProcess (inherited via DescribedObject → AbstractProcess → AggregateProcess):

Same AbstractProcess-level properties as Issue #19 (SimpleProcess). The DescribedObject-level properties (id, uniqueId, label, description, identifiers, classifiers, validTime, capabilities, characteristics, contacts, documents, history, securityConstraints, legalConstraints) may be parsed by shared helper functions that the main parser (Issue #22) coordinates.

Property Type Required OGC Spec Description
type 'AggregateProcess' (const) Yes Part 1 L3705 Type discriminator
definition string (URI) No Part 1 L3608 Process type as URI to ontology concept
typeOf link-2 No Part 1 L3612 Reference to base process this inherits from
configuration Settings No Part 1 L3616 Value settings constraining base process properties
featuresOfInterest FeatureList (link-2[]) No Part 1 L3619 Sampling/domain features relevant to process
inputs InputList (IOComponentChoice[]) No Part 1 L3623 Process input specifications
outputs OutputList (IOComponentChoice[]) No Part 1 L3626 Process output specifications
parameters ParameterList (IOComponentChoice[]) No Part 1 L3629 Configuration parameters
modes Mode[] No Part 1 L3632 Operating modes with configurations

AggregateProcess-specific properties:

Property Type Required OGC Spec Description
components ComponentList No Part 1 L3708 Array of named sub-processes
connections ConnectionList No Part 1 L3710 Data flow links between component inputs/outputs/parameters

ComponentList Structure (Part 1 L4112 / AggregateProcess.$defs L3715)

ComponentList is an array (minItems: 1) where each entry is:

SoftNamedProperty + oneOf(SimpleProcess | AggregateProcess | PhysicalComponent | PhysicalSystem | link-2)
  • name (required string, from SoftNamedProperty) — identifier matching ^[A-Za-z][A-Za-z0-9_\-]*$
  • Inline process: Any of the 4 concrete process types (recursive!)
  • External link (link-2 with type: 'Link'): Reference to externally-defined component

The parser must:

  1. Extract the name from each component entry
  2. Determine whether the entry is an inline process or external link
  3. For inline processes: recursively parse using the appropriate sub-parser (or delegate to main parser)
  4. For external links: preserve the link structure for later resolution

ConnectionList Structure (Part 1 L4127 / AggregateProcess.$defs L3730)

ConnectionList is an array (minItems: 1) where each entry has:

  • source (required PathRef string) — e.g., "components/sensor1/outputs/temperature"
  • destination (required PathRef string) — e.g., "outputs/temperature"

PathRef pattern: ^(components|inputs|outputs|parameters|modes)/([A-Za-z][A-Za-z0-9_\-]*/)*[A-Za-z][A-Za-z0-9_\-]*$

The parser must:

  1. Parse each connection entry extracting source and destination
  2. Validate that both source and destination are present (required per spec)
  3. Optionally validate path format against the PathRef regex pattern

Error Handling

  • Throw a descriptive error if type is not 'AggregateProcess'
  • Throw if components array contains entries without required name property
  • Throw if connections array contains entries missing source or destination
  • Handle missing optional properties gracefully (return undefined)
  • Handle recursive component parsing errors gracefully with context about which component failed

JSDoc Requirements

  • Document parseAggregateProcess 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., parseComponentList, parseConnectionList, parseComponentEntry)
  • Explain the recursive nature of component parsing in the function documentation
  • Follow the JSDoc style in src/ogc-api/edr/model.ts

Testing Requirements

  • Create src/ogc-api/csapi/formats/sensorml/aggregate-process.spec.ts (~150-200 lines)
  • Minimal valid document: Test parsing an AggregateProcess with only type + required DescribedObject props
  • Component parsing: Test with inline SimpleProcess and PhysicalComponent components
  • External link components: Test with link-2 component entries (type: 'Link', href)
  • Connection handling: Test parsing connections with valid source/destination PathRef strings
  • Nested component parsing: Test with an AggregateProcess containing another AggregateProcess as a component (recursive)
  • Mixed components: Test with a mix of inline processes and external links
  • Invalid document handling: Test with missing type, wrong type value, components missing name, connections missing source/destination
  • Edge cases: Test with empty components/connections arrays, single component, unknown extra 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/aggregate-process.ts exists with parseAggregateProcess function
  • Parser handles all AbstractProcess-level properties (definition, typeOf, configuration, featuresOfInterest, inputs, outputs, parameters, modes)
  • Parser handles ComponentList — named entries with inline process parsing and external link handling
  • Parser handles ConnectionList — source/destination PathRef pairs with validation
  • Recursive component parsing works (AggregateProcess containing AggregateProcess)
  • Descriptive errors thrown for invalid AggregateProcess documents
  • All new code has complete JSDoc documentation with @see links
  • aggregate-process.spec.ts exists with tests for component parsing, connection handling, recursion, invalid documents, and edge cases
  • Existing tests still pass (npm test)
  • No lint errors

Dependencies

Blocked by:

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 AggregateProcess interface, ComponentList, ConnectionList, ComponentEntry, Connection types
3 src/ogc-api/edr/model.ts Full file (126 lines) Blueprint: function structure, JSDoc style, discriminated unions
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) AggregateProcess, ComponentList, ConnectionList, ComponentEntry, Connection, IOComponentChoice, Mode, Settings
2 src/ogc-api/csapi/formats/swecommon/types.ts (Issue #17) SWEDataComponent / AnyComponent (via import type only)

Sibling References (same pattern)

# Document What It Provides
1 src/ogc-api/csapi/formats/sensorml/simple-process.ts (Issue #19) Sibling sub-parser for SimpleProcess — follow same structure for AbstractProcess-level parsing

Research References (context, not required reading)

# Document What It Provides
1 docs/planning/ROADMAP.md (Lines 417-425) 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 AggregateProcess schema (L3698), ComponentList (L4112 + AggregateProcess.$defs L3715), ConnectionList (L4127 + L3730), PathRef (L3299), SoftNamedProperty (L1938), AbstractProcess (L3599)
3 OGC API - Connected Systems Part 1 (23-001) API-level requirements for SensorML encoding

Convention Quick Reference

Rule Example
Use .js extension for relative imports import type { AggregateProcess } from './types.js'
Use import type for interfaces/types import type { AggregateProcess } from './types.js'
Three-tier hierarchy: import from lower tiers only shared → ogc-api → csapi
Named exports for types and utilities export function parseAggregateProcess(json: unknown): AggregateProcess
HTTP mocking: globalThis.fetch = jest.fn() Never use nock, msw, or other libraries
Meaningful tests only Verify parsed component names, connection paths, 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