colca-data-contracts 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/PKG-INFO +1 -1
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/pyproject.toml +1 -1
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/__init__.py +7 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/payload.py +66 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/routing.py +3 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts.egg-info/PKG-INFO +1 -1
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_alarm_payloads.py +76 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_bundle_generator.py +43 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/README.md +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/setup.cfg +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/annotation_types/platform.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/architecture_metadata.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/__init__.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/loader.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/machine.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/machinestate.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/oee_producer.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/oee_result.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/data_models/packmlmachine.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/icons.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/local_service.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/logging.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/machine_state.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/metadata_types/platform.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/observability.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/platform_tags.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/py.typed +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/quantities.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/root.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/semantic_tags/platform.yaml +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/semantic_types.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/service_topics.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/topics.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/annotation_id.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/authz_objects.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/data_model_vocabulary.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/grant_evaluation.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/log_payload.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/manifest_streams.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/metric_rows.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/replication_policy.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/sanitize.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/service_context.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/signal_data_types.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/vectors/topic_transformations.json +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts.egg-info/SOURCES.txt +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts.egg-info/dependency_links.txt +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts.egg-info/requires.txt +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts.egg-info/top_level.txt +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_annotation_payload.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_data_models_builtin.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_data_models_loader.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_data_models_vocabulary.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_local_service.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_log_payload_vector.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_machine_state.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_metric_value_types.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_observability.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_platform_tags.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_projection_payloads.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_quantities.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_replication_policy.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_signal_data_type.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_topic_root.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_topic_vectors.py +0 -0
- {colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_topology_payloads.py +0 -0
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "colca-data-contracts"
|
|
7
7
|
# Release builds take the version from the git tag.
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.3.0"
|
|
9
9
|
description = "Payload contracts, topic helpers and golden vectors for Colca"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = { text = "FSL-1.1-ALv2" }
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/__init__.py
RENAMED
|
@@ -70,7 +70,10 @@ from colca_data_contracts.payload import (
|
|
|
70
70
|
ActorKind,
|
|
71
71
|
AlarmNotificationConfigSnapshot,
|
|
72
72
|
AlarmNotificationSummary,
|
|
73
|
+
AlarmSeverity,
|
|
74
|
+
AlarmState,
|
|
73
75
|
AlarmStateChange,
|
|
76
|
+
AlarmStatus,
|
|
74
77
|
AuditAction,
|
|
75
78
|
AuditEvent,
|
|
76
79
|
AuditOutcome,
|
|
@@ -203,6 +206,10 @@ __all__ = [ # noqa: RUF022 - grouped by topic
|
|
|
203
206
|
"AlarmNotificationSummary",
|
|
204
207
|
"AlarmStateChange",
|
|
205
208
|
"NotificationDispatched",
|
|
209
|
+
# The standing alarm, one retained record per alarm definition
|
|
210
|
+
"AlarmState",
|
|
211
|
+
"AlarmStatus",
|
|
212
|
+
"AlarmSeverity",
|
|
206
213
|
# Annotation instances, on their own stream like alarms
|
|
207
214
|
"AnnotationPayload",
|
|
208
215
|
"derive_annotation_id",
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/payload.py
RENAMED
|
@@ -131,6 +131,21 @@ class ActorKind(BaseStrEnum):
|
|
|
131
131
|
ANONYMOUS = "anonymous"
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
class AlarmStatus(BaseStrEnum):
|
|
135
|
+
"""What a standing alarm is doing. No ``normal`` and no ``recovered``: an
|
|
136
|
+
alarm that no longer stands is deleted, not set to a quiet status."""
|
|
137
|
+
|
|
138
|
+
PENDING = "pending"
|
|
139
|
+
FIRING = "firing"
|
|
140
|
+
UNKNOWN = "unknown"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class AlarmSeverity(BaseStrEnum):
|
|
144
|
+
INFO = "info"
|
|
145
|
+
WARNING = "warning"
|
|
146
|
+
CRITICAL = "critical"
|
|
147
|
+
|
|
148
|
+
|
|
134
149
|
class CustomEncoder(json.JSONEncoder):
|
|
135
150
|
def default(self, obj):
|
|
136
151
|
if isinstance(
|
|
@@ -144,6 +159,8 @@ class CustomEncoder(json.JSONEncoder):
|
|
|
144
159
|
AuditAction,
|
|
145
160
|
AuditOutcome,
|
|
146
161
|
ActorKind,
|
|
162
|
+
AlarmStatus,
|
|
163
|
+
AlarmSeverity,
|
|
147
164
|
),
|
|
148
165
|
):
|
|
149
166
|
return str(obj)
|
|
@@ -480,6 +497,55 @@ class NotificationDispatched(Payload):
|
|
|
480
497
|
terminal: bool = True
|
|
481
498
|
|
|
482
499
|
|
|
500
|
+
@dataclass
|
|
501
|
+
class AlarmState(Payload):
|
|
502
|
+
"""The alarm that stands right now: one record per alarm definition.
|
|
503
|
+
|
|
504
|
+
State, not an event. A new record replaces the one before it, and an empty
|
|
505
|
+
payload retires the path — that tombstone is "the alarm has gone". Nothing
|
|
506
|
+
else says so: there is no ``normal`` status, because what is not in the
|
|
507
|
+
key-value view is not standing. The transitions themselves stay events, on
|
|
508
|
+
the ``alarms`` stream as ``_AlarmStateChange``.
|
|
509
|
+
|
|
510
|
+
The record sits at the alarm's own element path,
|
|
511
|
+
``{root}/v1/_AlarmState/{node}/{element-path}/{alarm-name}``, so read
|
|
512
|
+
grants and zones reach it like any signal. ``_Alarm`` stays reserved for
|
|
513
|
+
the definition, which has another writer.
|
|
514
|
+
|
|
515
|
+
Recipients are deliberately absent: another writer owns them, they are
|
|
516
|
+
personal data that does not belong in the retained view, and a policy
|
|
517
|
+
change must never rewrite an alarm's state. Who was reached and when is in
|
|
518
|
+
``_NotificationDispatched``. No title or message either: the name comes
|
|
519
|
+
from the alarm's ``_SystemElement``, and the topic path is the link.
|
|
520
|
+
"""
|
|
521
|
+
|
|
522
|
+
alarm_id: ULID
|
|
523
|
+
status: AlarmStatus
|
|
524
|
+
severity: AlarmSeverity
|
|
525
|
+
#: Unix seconds this status has held since.
|
|
526
|
+
since: float
|
|
527
|
+
signal_id: ULID
|
|
528
|
+
#: Why it stands. ``threshold``, ``no_data`` and ``stream_gap`` are the
|
|
529
|
+
#: known values, but the vocabulary stays open so a derived diagnosis can
|
|
530
|
+
#: name its own reason.
|
|
531
|
+
reason: str
|
|
532
|
+
#: The measurement that brought it here, with the rule's operator and
|
|
533
|
+
#: threshold, so a reader can render "82.4 > 80" without the definition.
|
|
534
|
+
value: Any | None = None
|
|
535
|
+
op: str | None = None
|
|
536
|
+
threshold: float | None = None
|
|
537
|
+
#: The `_AlarmStateChange` this state came out of.
|
|
538
|
+
event_id: str | None = None
|
|
539
|
+
#: ``sub`` of the person, as the node witnessed it (the command's
|
|
540
|
+
#: actor_id), never self-asserted.
|
|
541
|
+
acknowledged_by: str | None = None
|
|
542
|
+
acknowledged_at: float | None = None
|
|
543
|
+
note: str | None = None
|
|
544
|
+
silenced_by: str | None = None
|
|
545
|
+
#: Unix seconds.
|
|
546
|
+
silenced_until: float | None = None
|
|
547
|
+
|
|
548
|
+
|
|
483
549
|
def derive_annotation_id(
|
|
484
550
|
annotation_type_id: str,
|
|
485
551
|
source: str,
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/routing.py
RENAMED
|
@@ -33,6 +33,9 @@ CLASS_TABLE: dict[str, str] = {
|
|
|
33
33
|
"_ExternalReference": "entity",
|
|
34
34
|
"_AlarmNotificationConfig": "entity",
|
|
35
35
|
"_NotificationConfigStatus": "entity",
|
|
36
|
+
# The standing alarm, one record per definition: it overwrites itself and
|
|
37
|
+
# a tombstone retires it, so a new subscriber sees what stands.
|
|
38
|
+
"_AlarmState": "entity",
|
|
36
39
|
# Alarm events: append-only, not in KV, not retained, and on their own
|
|
37
40
|
# stream so they never queue behind a metrics backlog.
|
|
38
41
|
"_AlarmStateChange": "alarm",
|
|
@@ -3,7 +3,10 @@ from franzmq import Topic
|
|
|
3
3
|
from colca_data_contracts import (
|
|
4
4
|
AlarmNotificationConfigSnapshot,
|
|
5
5
|
AlarmNotificationSummary,
|
|
6
|
+
AlarmSeverity,
|
|
7
|
+
AlarmState,
|
|
6
8
|
AlarmStateChange,
|
|
9
|
+
AlarmStatus,
|
|
7
10
|
NotificationChannelConfig,
|
|
8
11
|
NotificationChannelOutcome,
|
|
9
12
|
NotificationConfigStatus,
|
|
@@ -245,3 +248,76 @@ def test_dispatch_round_trip_includes_provider_delivery_result():
|
|
|
245
248
|
|
|
246
249
|
def test_service_types_include_notifications():
|
|
247
250
|
assert ServiceType.NOTIFICATIONS == "notifications"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_standing_alarm_is_one_retained_record_at_the_alarm_element():
|
|
254
|
+
state = AlarmState(
|
|
255
|
+
alarm_id="01H0000000000000000000ARM1",
|
|
256
|
+
status=AlarmStatus.FIRING,
|
|
257
|
+
severity=AlarmSeverity.CRITICAL,
|
|
258
|
+
since=1710000000.0,
|
|
259
|
+
signal_id="01H0000000000000000000SGN2",
|
|
260
|
+
reason="threshold",
|
|
261
|
+
value=82.4,
|
|
262
|
+
op=">",
|
|
263
|
+
threshold=80.0,
|
|
264
|
+
event_id="evt-1",
|
|
265
|
+
)
|
|
266
|
+
topic = Topic(payload_type=AlarmState, node_id="n-edge1", context=("line1", "press3", "overheat"))
|
|
267
|
+
|
|
268
|
+
assert str(topic) == "colca/v1/_AlarmState/n-edge1/line1/press3/overheat"
|
|
269
|
+
assert AlarmState.get_identifier() == "_AlarmState"
|
|
270
|
+
# The alarm is an element in the tree, not a reserved _colca path, so read
|
|
271
|
+
# grants and zones reach it like any signal.
|
|
272
|
+
assert "_colca" not in str(topic)
|
|
273
|
+
|
|
274
|
+
decoded = AlarmState.decode(state.encode(), timestamp=0)
|
|
275
|
+
|
|
276
|
+
assert decoded.status == "firing"
|
|
277
|
+
assert decoded.severity == "critical"
|
|
278
|
+
assert decoded.value == 82.4
|
|
279
|
+
assert decoded.op == ">"
|
|
280
|
+
assert decoded.threshold == 80.0
|
|
281
|
+
assert decoded.event_id == "evt-1"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_standing_alarm_carries_no_recipients_and_no_presentation():
|
|
285
|
+
fields = set(AlarmState.__dataclass_fields__)
|
|
286
|
+
|
|
287
|
+
# Recipients have another writer, are personal data, and a policy change
|
|
288
|
+
# must not rewrite an alarm's state; who was reached is _NotificationDispatched.
|
|
289
|
+
assert not fields & {"recipients", "channels", "policies", "policy_id", "recipient_id"}
|
|
290
|
+
# The name comes from the alarm's _SystemElement, the link is the topic.
|
|
291
|
+
assert not fields & {"title", "message", "deepLink", "deep_link"}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def test_standing_alarm_has_no_normal_status():
|
|
295
|
+
# "Gone" is the tombstone, not a status: what is not in the KV view is not
|
|
296
|
+
# standing.
|
|
297
|
+
assert {str(member) for member in AlarmStatus} == {"pending", "firing", "unknown"}
|
|
298
|
+
assert {str(member) for member in AlarmSeverity} == {"info", "warning", "critical"}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def test_acknowledgement_is_witnessed_by_the_node():
|
|
302
|
+
state = AlarmState(
|
|
303
|
+
alarm_id="01H0000000000000000000ARM1",
|
|
304
|
+
status=AlarmStatus.FIRING,
|
|
305
|
+
severity=AlarmSeverity.WARNING,
|
|
306
|
+
since=1710000000.0,
|
|
307
|
+
signal_id="01H0000000000000000000SGN2",
|
|
308
|
+
reason="no_data",
|
|
309
|
+
acknowledged_by="keycloak-sub-1",
|
|
310
|
+
acknowledged_at=1710000060.0,
|
|
311
|
+
note="Sensor wird getauscht",
|
|
312
|
+
silenced_by="keycloak-sub-1",
|
|
313
|
+
silenced_until=1710003600.0,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
decoded = AlarmState.decode(state.encode(), timestamp=0)
|
|
317
|
+
|
|
318
|
+
# The evaluator writes the actor_id the node witnessed, never a claim the
|
|
319
|
+
# payload made about itself.
|
|
320
|
+
assert decoded.acknowledged_by == "keycloak-sub-1"
|
|
321
|
+
assert decoded.acknowledged_at == 1710000060.0
|
|
322
|
+
assert decoded.note == "Sensor wird getauscht"
|
|
323
|
+
assert decoded.silenced_until == 1710003600.0
|
|
@@ -305,6 +305,48 @@ def test_alarm_notification_contracts_have_revised_direction_and_shape():
|
|
|
305
305
|
assert {"revision", "notification"} <= set(event["schema"]["required"])
|
|
306
306
|
|
|
307
307
|
|
|
308
|
+
def test_standing_alarm_is_retained_state_with_a_closed_status_vocabulary():
|
|
309
|
+
body, _ = gb.build_bundle()
|
|
310
|
+
standing = body["contracts"]["_AlarmState"]
|
|
311
|
+
schema = standing["schema"]
|
|
312
|
+
|
|
313
|
+
# One record per alarm definition: it overwrites itself, and the tombstone
|
|
314
|
+
# is how an alarm goes away.
|
|
315
|
+
assert standing["class"] == "entity"
|
|
316
|
+
assert standing["tombstone"] is True
|
|
317
|
+
assert set(schema["required"]) == {
|
|
318
|
+
"alarm_id",
|
|
319
|
+
"status",
|
|
320
|
+
"severity",
|
|
321
|
+
"since",
|
|
322
|
+
"signal_id",
|
|
323
|
+
"reason",
|
|
324
|
+
}
|
|
325
|
+
# Status and severity are closed; reason stays open so a derived diagnosis
|
|
326
|
+
# can name its own.
|
|
327
|
+
assert schema["properties"]["status"]["enum"] == ["pending", "firing", "unknown"]
|
|
328
|
+
assert schema["properties"]["severity"]["enum"] == ["info", "warning", "critical"]
|
|
329
|
+
assert "enum" not in schema["properties"]["reason"]
|
|
330
|
+
|
|
331
|
+
validator = jsonschema.Draft202012Validator(schema)
|
|
332
|
+
standing_now = {
|
|
333
|
+
"alarm_id": "01H0000000000000000000ARM1",
|
|
334
|
+
"status": "firing",
|
|
335
|
+
"severity": "critical",
|
|
336
|
+
"since": 1710000000.0,
|
|
337
|
+
"signal_id": "01H0000000000000000000SGN2",
|
|
338
|
+
"reason": "threshold",
|
|
339
|
+
"value": 82.4,
|
|
340
|
+
"op": ">",
|
|
341
|
+
"threshold": 80.0,
|
|
342
|
+
}
|
|
343
|
+
validator.validate(standing_now)
|
|
344
|
+
# There is no "normal": an alarm that no longer stands is deleted.
|
|
345
|
+
assert not validator.is_valid({**standing_now, "status": "normal"})
|
|
346
|
+
assert not validator.is_valid({**standing_now, "status": "recovered"})
|
|
347
|
+
assert validator.is_valid({**standing_now, "reason": "compressor_stall"})
|
|
348
|
+
|
|
349
|
+
|
|
308
350
|
def test_alarm_channel_schema_requires_sealed_secret_and_rejects_cleartext_fields():
|
|
309
351
|
body, _ = gb.build_bundle()
|
|
310
352
|
channel = body["contracts"]["_AlarmNotificationConfig"]["schema"]["properties"]["channels"]["items"]
|
|
@@ -405,6 +447,7 @@ ULID_CONSTRAINED_FIELDS = {
|
|
|
405
447
|
"_Constant": ["id", "system_element_id", "semantic_type_id"],
|
|
406
448
|
"_Resource": ["id", "system_element_id"],
|
|
407
449
|
"_ExternalReference": ["id", "external_system_id"],
|
|
450
|
+
"_AlarmState": ["alarm_id", "signal_id"],
|
|
408
451
|
# annotation_type_id stays unconstrained until the golden annotation-id
|
|
409
452
|
# vectors derive from ULID type ids — see payload.Annotation.
|
|
410
453
|
"_Annotation": ["annotation_id", "signal_ids/items"],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/local_service.py
RENAMED
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/logging.py
RENAMED
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/machine_state.py
RENAMED
|
File without changes
|
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/observability.py
RENAMED
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/platform_tags.py
RENAMED
|
File without changes
|
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/quantities.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/semantic_types.py
RENAMED
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/service_topics.py
RENAMED
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/src/colca_data_contracts/topics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{colca_data_contracts-0.2.0 → colca_data_contracts-0.3.0}/tests/test_data_models_vocabulary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|