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
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
Related Issues
- #102 — URL builder nested paths (DEFERRED); workaround required extracting
controlstream@id from raw JSON — the exact gap this issue addresses
- #100 —
assertResourceAvailable() overly strict (DEFERRED); related Part 2 interoperability theme
- #101 —
parseDataRecord() complex types (FIX applied); similar spec-conformance gap precedent
- ogc-csapi-explorer#32 — Command status history; first encountered missing
controlstream@id
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:parseDatastream()system@id,system@linksystemRequiredparseControlStream()system@id,system@linksystemRequiredparseObservation()datastream@id,samplingFeature@id,foi@iddatastreamRequiredparseCommand()controlstream@idcontrolstreamRequiredparseCommandStatus()command@idcommandRequiredEach parser's JSDoc explicitly says "intentionally ignored" and the test suite has ~10
not.toHavePropertyassertions verifying the stripping.Evidence:
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
src/ogc-api/csapi/model.tssrc/ogc-api/csapi/formats/part2.ts@idfields using existing tolerant extraction patternsrc/ogc-api/csapi/formats/part2.spec.tsnot.toHavePropertyassertions; add extraction testsProposed 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?: stringControlStream.systemId?: stringObservation.datastreamId?: string,samplingFeatureId?: string,featureOfInterestId?: stringCommand.controlStreamId?: stringCommandStatus.commandId?: stringParser extraction (same
typeof obj['field'] === 'string' ? { fieldName: ... } : {}pattern):Scope boundary —
@linkfields: The minimum viable fix extracts@idfields only (simple strings). The@linkstructured objects ({ href, uid?, title? }) are a lower-priority addition that can be deferred to keep the initial diff smaller.Scope — What NOT to Touch
linksarray handling —@idextraction is additive, not a replacementurl_builder.ts— that issue is tracked separately ([SPLIT] assertResourceAvailable() overly strict for per-ID methods → #156 + #157 #100, [DEFERRED] URL builder: command/observation CRUD methods require top-level endpoints, fail on nested-only servers #102)assertResourceAvailable()— that issue is tracked separately ([SPLIT] assertResourceAvailable() overly strict for per-ID methods → #156 + #157 #100)@linkstructured objects in the initial fix — scope to@idstrings onlyAcceptance Criteria
model.tshas optional cross-reference fields on all 5 Part 2 interfacespart2.tsparsers extract@idfields using the existing tolerant extraction pattern?) — zero impact on existing consumerspart2.spec.ts~10not.toHavePropertyassertions updated to verify extractionnpm test)tsc --noEmit)Dependencies
Blocked by: Nothing
Blocks: Nothing (purely additive)
Operational Constraints
Key constraints:
@idfields onlyReferences
@id/@linkfieldssrc/ogc-api/csapi/formats/part2.tssrc/ogc-api/csapi/model.tsAI_OPERATIONAL_CONSTRAINTS.mdRelated Issues
controlstream@idfrom raw JSON — the exact gap this issue addressesassertResourceAvailable()overly strict (DEFERRED); related Part 2 interoperability themeparseDataRecord()complex types (FIX applied); similar spec-conformance gap precedentcontrolstream@id