| 0 |
docs/code-review/008-pending-p2-raw-json-spread-into-typed-result.md |
Original finding with full context and ownership assessment |
| 1 |
src/ogc-api/csapi/formats/sensorml/physical-system.ts L411-438 |
Primary affected code — spread + coerce + delete-reassign in parsePhysicalSystem |
| 2 |
src/ogc-api/csapi/formats/sensorml/aggregate-process.ts L126-155 |
Same pattern in parseAggregateProcess |
| 3 |
src/ogc-api/csapi/formats/sensorml/simple-process.ts L105-130 |
Same pattern in parseSimpleProcess |
| 4 |
OGC SensorML 3.0 (23-000r1) |
Defines the four concrete process types (SimpleProcess, AggregateProcess, PhysicalComponent, PhysicalSystem) and their JSON structure |
| 5 |
OGC SWE Common 3.0 (23-011r1) |
Defines capabilities, characteristics, and parameters structures nested inside SensorML JSON — part of the raw spread |
| 6 |
OGC API — Connected Systems Part 1 (23-001) |
Establishes SensorML encoding requirements for Part 1 resources |
| 7 |
docs/research/standards/ogcapi-connectedsystems-1.bundled.oas31.yaml |
Machine-readable response schema — authoritative source for expected field types |
| 8 |
OGC API — Features (17-069r4) |
Foundation parser pattern the SensorML parsers should follow |
| 9 |
GeoJSON (RFC 7946) |
Library's GeoJSON parser establishes the expected pattern for typed object construction from parsed JSON |
| 10 |
JSON Schema |
SensorML 3.0 has JSON Schemas for validation — relevant to whether raw JSON should be spread without checking |
| 11 |
docs/research/references.md |
Full project reference catalog |
| 12 |
camptocamp/ogc-client |
Upstream library with format handler patterns and quality bar for PR acceptance |
| 13 |
OS4CSAPI/ogc-client-CSAPI_2 |
This repository containing the affected SensorML parser files |
| 14 |
docs/research/requirements/contribution-definition.md |
Format abstraction layer requirements and production-ready implementation goals |
| 15 |
docs/research/requirements/csapi-52north-analysis.md |
Server format variations — different servers could send unexpected field types |
| 16 |
docs/research/requirements/csapi-datatype-schema-requirements.md |
50+ TypeScript interfaces — the type system the as casts bypass |
| 17 |
docs/research/requirements/csapi-format-requirements-3.1.md |
Parsing vs pass-through requirements for format handlers |
| 18 |
docs/research/requirements/csapi-format-requirements.md |
Comprehensive format requirements including SensorML 3.0 parsing needs |
| 19 |
docs/research/requirements/csapi-gap-analysis.md |
Gap analysis — incomplete format parsing led to prior rejection |
| 20 |
docs/research/requirements/csapi-opensensorhub-analysis.md |
Primary server whose SensorML responses the parsers must safely handle |
| 21 |
docs/research/requirements/csapi-oscarviewer-analysis.md |
Real-world TypeScript CSAPI client — type safety reference |
| 22 |
docs/research/requirements/csapi-oshconnect-python-analysis.md |
Pydantic runtime validation — contrasts the finding's lack of runtime checks |
| 23 |
docs/research/requirements/OSHConnect-Python-Analysis.md |
Generic type system and Pydantic validation pattern reference |
| 24 |
docs/research/requirements/csapi-owslib-analysis.md |
Mature client library with class-per-resource typed construction |
| 25 |
docs/research/requirements/csapi-part1-requirements.md |
GeoJSON and SensorML format requirements for Part 1 resources |
| 26 |
docs/research/requirements/csapi-usage-scenarios.md |
Error handling requirements and common error patterns |
| 27 |
docs/research/requirements/lessons-learned-analysis.md |
Under-engineering gaps — unsafe casts are an under-engineering mistake |
| 28 |
docs/research/requirements/upstream-expectations.md |
Quality standards expected by camptocamp — unsafe casts risk PR rejection |
| 29 |
docs/research/upstream/architecture-patterns-analysis.md |
Upstream architectural patterns parsers should follow |
| 30 |
docs/research/upstream/code-reuse-analysis.md |
Code reuse vs duplication strategy for shared utilities |
| 31 |
docs/research/upstream/csapi-architecture-analysis.md |
SWE Common/SensorML integration architecture decisions |
| 32 |
docs/research/upstream/error-handling-analysis.md |
Error handling patterns at parse boundaries |
| 33 |
docs/research/upstream/format-negotiation-analysis.md |
Format detection for application/sml+json — integration with SensorML handlers |
| 34 |
docs/research/upstream/pr114-analysis.md |
EDR implementation blueprint — test patterns and quality reference |
| 35 |
docs/research/upstream/typescript-types-analysis.md |
Type safety strategies and enforcement patterns |
| 36 |
docs/research/design/csapiquerybuilder/architecture-decision/ |
Architecture decisions series including multi-class failure analysis |
| 37 |
docs/research/strategy/design-strategy-research.md |
Format abstraction layer architecture design context |
| 38 |
docs/research/testing/testing-strategy-research.md |
Overall testing approach and coverage targets |
| 39 |
docs/research/testing/research-plans/09-sensorml-testing-requirements.md |
SensorML parser testing requirements |
| 40 |
docs/research/testing/research-plans/10-swe-common-testing-requirements.md |
SWE Common testing requirements — nested inside SensorML |
| 41 |
docs/research/testing/research-plans/03-typescript-testing-standards.md |
TypeScript testing standards including type safety verification |
| 42 |
docs/research/testing/research-plans/18-error-condition-testing.md |
Error condition coverage — wrong-type fields are edge conditions |
| 43 |
docs/research/testing/review/notes-parser-testing-vs-spec-validation.md |
Parser testing vs spec validation philosophy — trust boundary context |
| 44 |
docs/research/testing/review/notes-why-models-default-to-server-validation.md |
Why parsers default to server validation — guards against turning fix into validation gate |
| 45 |
docs/planning/csapi-implementation-guide.md |
Architecture reference — format handler design requirements |
| 46 |
docs/planning/contribution-goal-and-definition.md |
Acceptance criteria for upstream PR |
| 47 |
docs/planning/phase-5/P5-parser-completion-implementation-guide.md |
Parser function signatures and field mapping specifications — defines how parsers should construct typed results |
| 48 |
docs/planning/phase-5/P5-contribution-goal-and-definition.md |
Per-parser acceptance criteria and coverage requirements |
| 49 |
docs/planning/phase-6/P6-implementation-guide.md |
Code quality normalization — the raw-spread pattern may need normalization |
| 50 |
docs/planning/phase-6/P6-contribution-goal-and-definition.md |
Upstream acceptance readiness quality bar |
| 51 |
docs/governance/known-server-quirks.md |
Known server non-compliant behaviors — servers could send unexpected types |
| 52 |
docs/governance/phase-2-lessons-learned.md |
Code review and testing strategy lessons |
| 53 |
docs/governance/phase-3-lessons-learned.md |
Format handler development insights and SWE Common complexity management |
| 54 |
docs/governance/code-review-prompt-template-phase-6.md |
Phase 6 code review quality criteria |
| 55 |
docs/governance/issue-creation-prompt-template-code-review.md |
Template C for code review issue creation — the process that produced this issue |
| 56 |
docs/implementation/final-project-code-review.md |
End-to-end code review prior to upstream — context on why this was missed |
| 57 |
docs/implementation/phase-5.3-code-review.md |
Phase 5.3 code review of schema response parsers — adjacent parser quality standards context |
| 58 |
docs/implementation/phase-5.4-code-review.md |
Code review finding resolutions and smoke test results |
| 59 |
docs/implementation/design-notes-validation-extraction-decoupling.md |
Validation/extraction decoupling — the design principle the fix should follow |
| 60 |
docs/implementation/deferred-findings-final-disposition.md |
Deferred findings — may document prior awareness of this pattern |
| 61 |
docs/implementation/outstanding-findings-status-report.md |
Outstanding findings context |
| 62 |
docs/testing/fixtures-guide.md |
Fixture creation for wrong-type test cases |
| 63 |
docs/testing/demo-app-findings/issue-12-constructor-parameter-narrowing.md |
Constructor parameter narrowing — same class of type-safety gap |
| 64 |
docs/testing/demo-app-findings/issue-13-type-guard-functions-for-union-narrowing.md |
Type guard utilities — recommended pattern to replace unsafe as casts |
| 65 |
Upstream PR #136 |
Upstream contribution — jahow's review requirements affect PR acceptance |
| 66 |
OpenSensorHub Demo Server |
Primary live server providing SensorML responses the parsers must safely deserialize |
| 67 |
52°North Demo Server |
Secondary server with format variations — responses may differ from OSH |
| 68 |
docs/planning/ROADMAP.md |
Master roadmap — phase progression context |
Finding
physical-system.ts,aggregate-process.ts, andsimple-process.tsall construct their typed result objects by spreading raw (unvalidated) server JSON via...(json as Record), then coercing required fields withas stringand using a delete-then-reassign mutation pattern to overwrite managed keys.Review Source: Senior developer code review of
clean-prSeverity: P2-Important
Category: Type Safety
Ownership: Ours
Problem Statement
All three SensorML process-type parsers construct their typed result objects by:
...(json as Record)label,uniqueId) withas string— notypeofcheckThis means any field the server sends with the wrong type (e.g.
"label": 42) lands on the typed result object without any runtime error. TypeScript believes the result isPhysicalSystem(orAggregateProcess/SimpleProcess) but any field could actually be the wrong type. The delete-then-reassign mutation pattern is also fragile and non-obvious.Affected code:
Same pattern at:
aggregate-process.tslines 126–134 (spread + coerce)simple-process.tslines 105–113 (spread + coerce)Scenario:
Impact: All consumers of the parsed SensorML types receive objects whose fields may silently have the wrong type. The type guarantee is hollow — if
label.toUpperCase()is called downstream, it would throwTypeError: label.toUpperCase is not a functionwith no indication that the error originates from upchecked deserialization. Additionally, the delete-then-reassign mutation pattern makes the code fragile — if a new managed key is added but themanagedKeysarray is not updated, the raw value leaks through.Ownership Verification
All three affected files are entirely within the
csapi/isolation boundary and have zero commits onupstream/main:Git blame of affected lines:
physical-system.tsL411-4160060356faggregate-process.tsL129-134814aef64simple-process.tsL108-113242c2bfaConclusion: This code is ours. All three files are entirely within the
csapi/isolation boundary and do not exist in upstream camptocamp/ogc-client.Files to Modify
src/ogc-api/csapi/formats/sensorml/physical-system.tssrc/ogc-api/csapi/formats/sensorml/aggregate-process.tssrc/ogc-api/csapi/formats/sensorml/simple-process.tssrc/ogc-api/csapi/formats/sensorml/physical-system.spec.tssrc/ogc-api/csapi/formats/sensorml/aggregate-process.spec.tssrc/ogc-api/csapi/formats/sensorml/simple-process.spec.tsProposed Solutions
Option A: Construct result explicitly field-by-field
Pros: No raw spread; no delete-then-reassign mutation; type checks are explicit; guaranteed to match the TypeScript interface.
Cons: More verbose; all DescribedObject fields must be listed explicitly. SensorML has a very large optional field surface area.
Effort: Medium | Risk: Low
Option B: Keep spread, add runtime type checks for required fields only (Recommended)
And replace the delete-then-reassign pattern with explicit field assignment (either two-stage construction or
Object.assign).Pros: Less verbose; retains spread for optional fields (pragmatic given SensorML's large optional surface area); adds guards for required fields; eliminates
as stringcoercions.Cons: Still spreads unknown optional fields without validation. Optional fields remain unguarded.
Effort: Small | Risk: Low
Recommended Action
Option B — pragmatic middle ground that eliminates the silent coercions on required fields while acknowledging that SensorML has a very large optional field surface area where exhaustive validation would be impractical. The delete-then-reassign mutation should also be replaced with explicit field assignment.
Scope — What NOT to Touch
_helpers.ts,parser.ts) — they are not part of this findingPhysicalSystem,AggregateProcess,SimpleProcess) remain the sameAcceptance Criteria
label,uniqueId,type) are type-checked before assignment — wrong type produces a clearError, not a silent coercionas stringcasts onlabelanduniqueIdare replaced withtypeofguardsphysical-system.ts,aggregate-process.ts,simple-process.ts) are updated consistentlylabelis not a string; parser throws whenuniqueIdis not a stringnpm test)npm run lint)npx prettier --checkDependencies
Blocked by: Nothing
Blocks: Nothing
Related: #141 —
parseCollectionResponseunchecked generic cast (same category: type-safety at trust boundaries); #143 —extractCSAPIFeatureproperties null cast (same category: unsafeascast in format handler)Operational Constraints
Key constraints:
phase-6branchOwnership-Specific Constraints
This is Ours:
phase-6branch (or the current working branch)clean-prif the PR is still openReferences
docs/code-review/008-pending-p2-raw-json-spread-into-typed-result.mdsrc/ogc-api/csapi/formats/sensorml/physical-system.tsL411-438parsePhysicalSystemsrc/ogc-api/csapi/formats/sensorml/aggregate-process.tsL126-155parseAggregateProcesssrc/ogc-api/csapi/formats/sensorml/simple-process.tsL105-130parseSimpleProcessdocs/research/standards/ogcapi-connectedsystems-1.bundled.oas31.yamldocs/research/references.mddocs/research/requirements/contribution-definition.mddocs/research/requirements/csapi-52north-analysis.mddocs/research/requirements/csapi-datatype-schema-requirements.mdascasts bypassdocs/research/requirements/csapi-format-requirements-3.1.mddocs/research/requirements/csapi-format-requirements.mddocs/research/requirements/csapi-gap-analysis.mddocs/research/requirements/csapi-opensensorhub-analysis.mddocs/research/requirements/csapi-oscarviewer-analysis.mddocs/research/requirements/csapi-oshconnect-python-analysis.mddocs/research/requirements/OSHConnect-Python-Analysis.mddocs/research/requirements/csapi-owslib-analysis.mddocs/research/requirements/csapi-part1-requirements.mddocs/research/requirements/csapi-usage-scenarios.mddocs/research/requirements/lessons-learned-analysis.mddocs/research/requirements/upstream-expectations.mddocs/research/upstream/architecture-patterns-analysis.mddocs/research/upstream/code-reuse-analysis.mddocs/research/upstream/csapi-architecture-analysis.mddocs/research/upstream/error-handling-analysis.mddocs/research/upstream/format-negotiation-analysis.mdapplication/sml+json— integration with SensorML handlersdocs/research/upstream/pr114-analysis.mddocs/research/upstream/typescript-types-analysis.mddocs/research/design/csapiquerybuilder/architecture-decision/docs/research/strategy/design-strategy-research.mddocs/research/testing/testing-strategy-research.mddocs/research/testing/research-plans/09-sensorml-testing-requirements.mddocs/research/testing/research-plans/10-swe-common-testing-requirements.mddocs/research/testing/research-plans/03-typescript-testing-standards.mddocs/research/testing/research-plans/18-error-condition-testing.mddocs/research/testing/review/notes-parser-testing-vs-spec-validation.mddocs/research/testing/review/notes-why-models-default-to-server-validation.mddocs/planning/csapi-implementation-guide.mddocs/planning/contribution-goal-and-definition.mddocs/planning/phase-5/P5-parser-completion-implementation-guide.mddocs/planning/phase-5/P5-contribution-goal-and-definition.mddocs/planning/phase-6/P6-implementation-guide.mddocs/planning/phase-6/P6-contribution-goal-and-definition.mddocs/governance/known-server-quirks.mddocs/governance/phase-2-lessons-learned.mddocs/governance/phase-3-lessons-learned.mddocs/governance/code-review-prompt-template-phase-6.mddocs/governance/issue-creation-prompt-template-code-review.mddocs/implementation/final-project-code-review.mddocs/implementation/phase-5.3-code-review.mddocs/implementation/phase-5.4-code-review.mddocs/implementation/design-notes-validation-extraction-decoupling.mddocs/implementation/deferred-findings-final-disposition.mddocs/implementation/outstanding-findings-status-report.mddocs/testing/fixtures-guide.mddocs/testing/demo-app-findings/issue-12-constructor-parameter-narrowing.mddocs/testing/demo-app-findings/issue-13-type-guard-functions-for-union-narrowing.mdascastsdocs/planning/ROADMAP.md