Skip to content

Parsed Part 2 models discard all cross-reference fields — parent resource navigation impossible without raw JSON #103

@Sam-Bolling

Description

@Sam-Bolling

Task

Preserve OGC 23-002 Required cross-reference fields (system@id, datastream@id, controlstream@id, command@id, etc.) in the five Part 2 parser functions by adding optional parent-reference properties to model interfaces and extracting them during parsing.

Finding Reference: Demo app finding from ogc-csapi-explorer commit ecce874 (parent navigation breadcrumbs) and ogc-csapi-explorer#32 (command status history)
Severity: Moderate
Category: Design gap — spec-required associations discarded during parsing
Ownership: Ours


Problem Statement

The five Part 2 parser functions (parseDatastream, parseControlStream, parseObservation, parseCommand, parseCommandStatus) intentionally discard all cross-reference fields present in the raw JSON. These fields encode Required parent–child associations per OGC 23-002 resource model tables:

Parser Discarded Fields Spec Table
parseDatastream() system@id, system@link Table 5 — system Required
parseControlStream() system@id, system@link Table 10 — system Required
parseObservation() datastream@id, samplingFeature@id, foi@id Table 7 — datastream Required
parseCommand() controlstream@id Table 12 — controlstream Required
parseCommandStatus() command@id Table 15 — command Required

Each parser's JSDoc explicitly says "intentionally ignored" and the test suite has ~10 not.toHaveProperty assertions verifying the stripping.

Evidence:

// ogc-csapi-explorer ResourceDetail.vue — must read from raw JSON, not parsed model
if (typeof raw['system@id'] === 'string') {
  links.push({ resourceType: 'systems', resourceId: raw['system@id'] })
}
if (typeof raw['datastream@id'] === 'string') {
  links.push({ resourceType: 'datastreams', resourceId: raw['datastream@id'] })
}

Impact: Any consumer wanting to navigate upward in the resource hierarchy (observation → datastream → system) must bypass typed models and work with raw JSON, undermining the purpose of having typed parsers.

Findings Report

Issue #103 Findings Report — Parsed Part 2 Models Discard Cross-Reference Fields

Recommendation: FIX — purely additive change (optional interface fields, same extraction pattern), zero backward-compatibility risk, strengthens spec conformance of the contribution.

Files to Create or Modify

File Action Est. Lines Purpose
src/ogc-api/csapi/model.ts Modify ~+15 Add optional cross-reference fields to 5 Part 2 interfaces
src/ogc-api/csapi/formats/part2.ts Modify ~+20 Extract @id fields using existing tolerant extraction pattern
src/ogc-api/csapi/formats/part2.spec.ts Modify ~+30 Update ~10 not.toHaveProperty assertions; add extraction tests

Proposed Fix

Add optional parent-reference fields to the 5 Part 2 model interfaces and extract them in the parsers using the same tolerant extraction pattern already in use.

Interface additions (all optional ?):

  • Datastream.systemId?: string
  • ControlStream.systemId?: string
  • Observation.datastreamId?: string, samplingFeatureId?: string, featureOfInterestId?: string
  • Command.controlStreamId?: string
  • CommandStatus.commandId?: string

Parser extraction (same typeof obj['field'] === 'string' ? { fieldName: ... } : {} pattern):

...(typeof obj['system@id'] === 'string'
  ? { systemId: obj['system@id'] as string }
  : {}),

Scope boundary — @link fields: The minimum viable fix extracts @id fields only (simple strings). The @link structured objects ({ href, uid?, title? }) are a lower-priority addition that can be deferred to keep the initial diff smaller.

Scope — What NOT to Touch

Acceptance Criteria

  • model.ts has optional cross-reference fields on all 5 Part 2 interfaces
  • part2.ts parsers extract @id fields using the existing tolerant extraction pattern
  • All new interface fields are optional (?) — zero impact on existing consumers
  • part2.spec.ts ~10 not.toHaveProperty assertions updated to verify extraction
  • New test cases verify extraction of each cross-reference field
  • Existing tests still pass (npm test)
  • No lint errors
  • No TypeScript compilation errors (tsc --noEmit)

Dependencies

Blocked by: Nothing
Blocks: Nothing (purely additive)


Operational Constraints

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

Key constraints:

  • Precedence: OGC specifications → AI Collaboration Agreement → This issue description → Existing code → Conversational context
  • No scope expansion: Fix the finding, nothing more — extract @id fields only
  • Minimal diffs: Use the identical tolerant extraction pattern already in every parser (~3–5 lines per function)
  • No refactoring: Do not change existing field types, reorder existing fields, or restructure parser logic
  • Backward compatibility is paramount: All new fields must be optional — existing consumers must see zero difference

References

# Document What It Provides
1 Findings Report Full analysis, risk assessment, and implementation guidance
2 OGC 23-002 Part 2 §9.2 (Table 5), §9.7 (Table 7), §10.2 (Table 10), §10.7 (Table 12), §10.11 (Table 15) Resource model association tables — Required associations
3 OGC 23-002 §16.1 §16.1.3–§16.1.9 JSON encoding examples showing @id/@link fields
4 src/ogc-api/csapi/formats/part2.ts 5 parsers to modify — extraction pattern blueprint
5 src/ogc-api/csapi/model.ts 5 Part 2 interfaces to extend
6 AI_OPERATIONAL_CONSTRAINTS.md Mandatory operational constraints

Related Issues

  • #102 — URL builder nested paths (DEFERRED); workaround required extracting controlstream@id from raw JSON — the exact gap this issue addresses
  • #100assertResourceAvailable() overly strict (DEFERRED); related Part 2 interoperability theme
  • #101parseDataRecord() complex types (FIX applied); similar spec-conformance gap precedent
  • ogc-csapi-explorer#32 — Command status history; first encountered missing controlstream@id

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions