-
Notifications
You must be signed in to change notification settings - Fork 0
samplingFeature@link silently dropped on Observation POST despite HTTP 201 acceptance #2
Description
Summary
OSH accepts samplingFeature@link on Observation POST requests (HTTP 201) but silently discards the field — it is not returned on subsequent GET. This prevents CSAPI-native linkage between Observations and their Feature of Interest (FOI).
This is the same "silent acceptance + silent discard" pattern documented in Issue #1 for deployedSystems@link and deployment@link.
| Operation | Result |
|---|---|
POST /samplingFeatures (create FOI) |
201 Created — persists and round-trips correctly |
POST /datastreams/{id}/observations with samplingFeature@link |
201 Created — accepted without error |
GET /observations/{id} (read back) |
samplingFeature@link absent — silently dropped |
Environment
- Server: OSH (OpenSensorHub) CSAPI instance on Oracle Cloud
- API root:
https://os4csapi-osh.duckdns.org/sensorhub/api - Date tested: 2026-03-03
- Encoding tested:
application/om+json
Context
The LOB Localizer system fuses Lines of Bearing from three acoustic sensor nodes to produce location-estimate Observations (rendered as gold ⊕ dots in the webapp). These observations need a featureOfInterest link to identify what they are about — in this case, a tracked UAS target.
Per SOSA/SSN, every sosa:Observation should reference a sosa:FeatureOfInterest. CSAPI Part 2 provides samplingFeature@link as the mechanism for this (OGC 23-002 §8.3.5).
Reproduction
1. Create SamplingFeature ✅
POST /sensorhub/api/samplingFeatures HTTP/1.1
Content-Type: application/json
{
"type": "Feature",
"properties": {
"uid": "urn:os4csapi:foi:uas-track-001",
"name": "UAS-Track-001",
"description": "Tracked UAS target identity for the AZ String Alpha sensor network.",
"featureType": "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/SF_SamplingPoint"
}
}HTTP 201 Created → Location: /samplingFeatures/040g
Read-back returns the full resource correctly. SamplingFeature CRUD works.
2. POST Observation with samplingFeature@link ✅ (accepted)
POST /sensorhub/api/datastreams/04f0/observations HTTP/1.1
Content-Type: application/om+json
{
"phenomenonTime": "2026-03-04T03:13:18.886Z",
"resultTime": "2026-03-04T03:13:18.886Z",
"samplingFeature@link": {
"href": "/samplingFeatures/040g",
"uid": "urn:os4csapi:foi:uas-track-001",
"title": "UAS-Track-001"
},
"result": {
"timestamp": 1772593998.953,
"trackId": 1,
"estimatedLat": 31.658,
"estimatedLon": -110.270,
"cep50_m": 50.0,
"classification": "UAS",
"numContributingLobs": 3,
"contributingSensors": "AZ-MA-1,AZ-MA-2,AZ-MA-3",
"residual_m": 30.0
}
}HTTP 201 Created → Location: /observations/041sthkupk339jq9g0
3. Read back ❌ (field dropped)
GET /sensorhub/api/observations/041sthkupk339jq9g0 HTTP/1.1
Accept: application/om+json{
"id": "041sthkupk339jq9g0",
"datastream@id": "04f0",
"phenomenonTime": "2026-03-04T03:13:18.886Z",
"resultTime": "2026-03-04T03:13:18.886Z",
"result": { "..." }
}samplingFeature@link is completely absent.
Cumulative Pattern
Third instance of the silent-accept/silent-discard behavior:
@link Field |
Resource Type | Spec Reference | Persists? |
|---|---|---|---|
deployedSystems@link |
Deployment | OGC 23-001 §8.5 | ❌ Dropped (#1) |
deployment@link |
DataStream | OGC 23-002 §7.3.2 | ❌ Dropped (#1) |
samplingFeature@link |
Observation | OGC 23-002 §8.3.5 | ❌ Dropped (this issue) |
platform@link |
Deployment | OGC 23-001 §8.5 | ✅ Works |
system@link |
DataStream | OGC 23-002 §7.3.2 | ✅ Works (read-only) |
Impact
Without persistence, clients cannot:
- Query observations by FOI (
GET /observations?samplingFeature={id}) - Group observations by subject identity through the API
- Build track-grouped displays without embedding track identity in the result blob as a workaround
Suggested Resolution
Option A — Persist the field: Store samplingFeature@link on Observation write, return it on read, support filtering by samplingFeature query parameter.
Option B — Reject unsupported fields: Return HTTP 422 when samplingFeature@link is provided but not supported, making the gap visible at write time.
Evidence
Full probe report with HTTP transcripts: