Skip to content

samplingFeature@link silently dropped on Observation POST despite HTTP 201 acceptance #2

Description

@Sam-Bolling

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:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions