-
Notifications
You must be signed in to change notification settings - Fork 0
Phase E1: semantic domain profiles for StreamSpec and CapabilitySpec #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
05b1ecf
79184bc
919275f
8ae0dcb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -93,6 +93,16 @@ class StreamSpec(_Frozen): | |||||||||||||||||
| adapter_digest: SHA256Hex | ||||||||||||||||||
| source: SourceLocator = "$" | ||||||||||||||||||
| role: Slug | None = None | ||||||||||||||||||
| dtype: str = "" | ||||||||||||||||||
| shape: tuple[int, ...] = () | ||||||||||||||||||
| unit: str = "" | ||||||||||||||||||
| coordinate_frame: str = "" | ||||||||||||||||||
| valid_range: tuple[float, float] | None = None | ||||||||||||||||||
| controller_id: str = "" | ||||||||||||||||||
| camera_calibration: dict[str, Any] = Field(default_factory=dict) | ||||||||||||||||||
| joint_order: tuple[str, ...] = () | ||||||||||||||||||
| invalid_depth_encoding: str = "" | ||||||||||||||||||
| privileged: bool = False | ||||||||||||||||||
|
|
||||||||||||||||||
| @model_validator(mode="after") | ||||||||||||||||||
| def _plugin_needs_schema(self) -> Self: | ||||||||||||||||||
|
|
@@ -155,11 +165,20 @@ class CapabilitySpec(_Frozen): | |||||||||||||||||
| features: tuple[Slug, ...] = () | ||||||||||||||||||
| modalities: tuple[Slug, ...] = () | ||||||||||||||||||
| schema_wildcard: bool = False | ||||||||||||||||||
| stream_profiles: tuple[StreamSpec, ...] = () | ||||||||||||||||||
| accepts_privileged: bool = False | ||||||||||||||||||
|
|
||||||||||||||||||
| @model_validator(mode="after") | ||||||||||||||||||
| def _non_empty_modes(self) -> Self: | ||||||||||||||||||
| def _validate_capability(self) -> Self: | ||||||||||||||||||
| if not self.interaction_modes: | ||||||||||||||||||
| raise TaskContractError(f"capability {self.interface} declares no interaction mode") | ||||||||||||||||||
| seen_ids: set[str] = set() | ||||||||||||||||||
| for s in self.stream_profiles: | ||||||||||||||||||
| if s.id in seen_ids: | ||||||||||||||||||
| raise TaskContractError( | ||||||||||||||||||
| f"capability {self.interface} declares duplicate stream_profile id {s.id!r}" | ||||||||||||||||||
| ) | ||||||||||||||||||
| seen_ids.add(s.id) | ||||||||||||||||||
| return self | ||||||||||||||||||
|
|
||||||||||||||||||
| def satisfies(self, interface: InterfaceSpec) -> bool: | ||||||||||||||||||
|
|
@@ -175,12 +194,78 @@ def satisfies(self, interface: InterfaceSpec) -> bool: | |||||||||||||||||
| for stream in interface.streams | ||||||||||||||||||
| ) | ||||||||||||||||||
| ) | ||||||||||||||||||
| return ( | ||||||||||||||||||
| if not ( | ||||||||||||||||||
| self.interface == interface.id | ||||||||||||||||||
| and interface.interaction_mode in self.interaction_modes | ||||||||||||||||||
| and interface.protocol_version in self.protocol_versions | ||||||||||||||||||
| and schemas_match | ||||||||||||||||||
| ) | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| cap_profiles: dict[Slug, StreamSpec] = {} | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P3] Duplicate stream_profiles ids silently overwrite each other
|
||||||||||||||||||
| if self.stream_profiles: | ||||||||||||||||||
| for s in self.stream_profiles: | ||||||||||||||||||
| if s.schema_id: | ||||||||||||||||||
| cap_profiles[s.schema_id] = s | ||||||||||||||||||
| if s.id: | ||||||||||||||||||
| cap_profiles[s.id] = s | ||||||||||||||||||
| for intf_stream in interface.streams: | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Fix stream_profiles lookup by schema_id
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Fix schema_id matching for stream_profiles In CapabilitySpec.satisfies(),
Suggested change
|
||||||||||||||||||
| has_semantics = bool( | ||||||||||||||||||
| intf_stream.unit | ||||||||||||||||||
| or intf_stream.coordinate_frame | ||||||||||||||||||
| or intf_stream.controller_id | ||||||||||||||||||
| or intf_stream.dtype | ||||||||||||||||||
| or intf_stream.shape | ||||||||||||||||||
| or intf_stream.joint_order | ||||||||||||||||||
| or intf_stream.invalid_depth_encoding | ||||||||||||||||||
| or intf_stream.valid_range is not None | ||||||||||||||||||
| or intf_stream.camera_calibration | ||||||||||||||||||
| ) | ||||||||||||||||||
| if has_semantics: | ||||||||||||||||||
| matching_profile = cap_profiles.get(intf_stream.id) or cap_profiles.get( | ||||||||||||||||||
| intf_stream.schema_id | ||||||||||||||||||
| ) | ||||||||||||||||||
| if matching_profile is None: | ||||||||||||||||||
| return False | ||||||||||||||||||
| if intf_stream.unit and matching_profile.unit != intf_stream.unit: | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.coordinate_frame | ||||||||||||||||||
| and matching_profile.coordinate_frame != intf_stream.coordinate_frame | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.controller_id | ||||||||||||||||||
| and matching_profile.controller_id != intf_stream.controller_id | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if intf_stream.dtype and matching_profile.dtype != intf_stream.dtype: | ||||||||||||||||||
| return False | ||||||||||||||||||
| if intf_stream.shape and matching_profile.shape != intf_stream.shape: | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.joint_order | ||||||||||||||||||
| and matching_profile.joint_order != intf_stream.joint_order | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.invalid_depth_encoding | ||||||||||||||||||
| and matching_profile.invalid_depth_encoding | ||||||||||||||||||
| != intf_stream.invalid_depth_encoding | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.valid_range is not None | ||||||||||||||||||
| and matching_profile.valid_range != intf_stream.valid_range | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if ( | ||||||||||||||||||
| intf_stream.camera_calibration | ||||||||||||||||||
| and matching_profile.camera_calibration != intf_stream.camera_calibration | ||||||||||||||||||
| ): | ||||||||||||||||||
| return False | ||||||||||||||||||
| if intf_stream.privileged and not self.accepts_privileged: | ||||||||||||||||||
| return False | ||||||||||||||||||
| return True | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class HarnessSpec(_Frozen): | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] camera_calibration is declared as a semantic profile field but never enforced
StreamSpec gains
camera_calibration: dict[str, Any]as one of the PR's domain-semantic profile fields, but the field is read nowhere else in the repo: it is missing from thehas_semanticscomputation inCapabilitySpec.satisfies()and there is nomatching_profile.camera_calibration != intf_stream.camera_calibrationcomparison alongside the other per-field checks. As a result, an interface stream whose only semantic declaration is a camera calibration hashas_semantics == Falseand binds to a capability with no stream profile at all, and two profiles with different calibrations bind as equivalent. That contradicts the PR's stated guarantee that equal tensor shapes with different physical meaning must refuse binding, and leaves the field dead in production code.