termwright 0.3.2__tar.gz → 0.4.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.
- {termwright-0.3.2 → termwright-0.4.0}/.gitignore +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/PKG-INFO +4 -4
- {termwright-0.3.2 → termwright-0.4.0}/README.md +3 -3
- {termwright-0.3.2 → termwright-0.4.0}/pyproject.toml +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/__init__.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/client.py +5 -6
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/messages.py +35 -7
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/roles.py +1 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/tree.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/validate.py +2 -2
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/__init__.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/textual_tree.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/tests/conftest.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_client.py +8 -8
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_messages.py +12 -4
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_probe_golden.py +3 -3
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_probe_session.py +4 -4
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_probe_tree.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_validate.py +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/uv.lock +1 -1
- {termwright-0.3.2 → termwright-0.4.0}/examples/permission_app.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/debug.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/errors.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/evidence.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/framing.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/limits.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/logging_bridge.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/logs.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/marker.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright/textual.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/__main__.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/bootstrap.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/defer.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/session.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/src/termwright_probe/textual_probe.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/fixtures/vanilla_textual_app.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_debug.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_evidence.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_framing.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_logs.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_marker.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_observation_vectors.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_probe_bootstrap.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_textual_annotations.py +0 -0
- {termwright-0.3.2 → termwright-0.4.0}/tests/test_textual_probe_hook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: termwright
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Semantic side-channel client, automatic Textual probe, and annotation SDK for Termwright
|
|
5
5
|
Project-URL: Homepage, https://github.com/gorce-ai/termwright
|
|
6
6
|
Project-URL: Source, https://github.com/gorce-ai/termwright/tree/main/clients/python
|
|
@@ -31,8 +31,8 @@ An instrumented app publishes its widget tree over a unix socket and commits
|
|
|
31
31
|
each render with a signed OSC marker, so the driver can assert on _roles and
|
|
32
32
|
names_ instead of screen-scraping cells.
|
|
33
33
|
|
|
34
|
-
The protocol client speaks `termwright/
|
|
35
|
-
is a complete
|
|
34
|
+
The protocol client speaks `termwright/3`. Every published semantic revision
|
|
35
|
+
is a complete v3 snapshot with evidence-qualified geometry and pointer
|
|
36
36
|
observations.
|
|
37
37
|
|
|
38
38
|
**Dormant rule.** Without `TERMWRIGHT_ENDPOINT` and `TERMWRIGHT_TOKEN` the
|
|
@@ -235,7 +235,7 @@ or, on a session that came up:
|
|
|
235
235
|
```text
|
|
236
236
|
tw:sem [p41207] 0.002s dial unix:/tmp/tw-8f21/s timeout=5000ms
|
|
237
237
|
tw:sem [p41207] 0.003s hello sent adapter=textual/1.0.0 caps=tree,states,actions,render-revisions,intended-geometry,clipped-geometry,pointer-hit-grid
|
|
238
|
-
tw:sem [3f9c1a04] 0.011s hello-ack session=3f9c1a04… marker=on subscribe=
|
|
238
|
+
tw:sem [3f9c1a04] 0.011s hello-ack session=3f9c1a04… marker=on subscribe=semantic logs=off
|
|
239
239
|
tw:io [3f9c1a04] 0.048s r1 snapshot nodes=17
|
|
240
240
|
```
|
|
241
241
|
|
|
@@ -7,8 +7,8 @@ An instrumented app publishes its widget tree over a unix socket and commits
|
|
|
7
7
|
each render with a signed OSC marker, so the driver can assert on _roles and
|
|
8
8
|
names_ instead of screen-scraping cells.
|
|
9
9
|
|
|
10
|
-
The protocol client speaks `termwright/
|
|
11
|
-
is a complete
|
|
10
|
+
The protocol client speaks `termwright/3`. Every published semantic revision
|
|
11
|
+
is a complete v3 snapshot with evidence-qualified geometry and pointer
|
|
12
12
|
observations.
|
|
13
13
|
|
|
14
14
|
**Dormant rule.** Without `TERMWRIGHT_ENDPOINT` and `TERMWRIGHT_TOKEN` the
|
|
@@ -211,7 +211,7 @@ or, on a session that came up:
|
|
|
211
211
|
```text
|
|
212
212
|
tw:sem [p41207] 0.002s dial unix:/tmp/tw-8f21/s timeout=5000ms
|
|
213
213
|
tw:sem [p41207] 0.003s hello sent adapter=textual/1.0.0 caps=tree,states,actions,render-revisions,intended-geometry,clipped-geometry,pointer-hit-grid
|
|
214
|
-
tw:sem [3f9c1a04] 0.011s hello-ack session=3f9c1a04… marker=on subscribe=
|
|
214
|
+
tw:sem [3f9c1a04] 0.011s hello-ack session=3f9c1a04… marker=on subscribe=semantic logs=off
|
|
215
215
|
tw:io [3f9c1a04] 0.048s r1 snapshot nodes=17
|
|
216
216
|
```
|
|
217
217
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "termwright"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Semantic side-channel client, automatic Textual probe, and annotation SDK for Termwright"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -33,7 +33,7 @@ from .messages import (
|
|
|
33
33
|
parse_driver_message,
|
|
34
34
|
protocol_error,
|
|
35
35
|
revision_commit,
|
|
36
|
-
|
|
36
|
+
semantic_full_message,
|
|
37
37
|
)
|
|
38
38
|
from .tree import SemanticSnapshot
|
|
39
39
|
from .validate import validate_snapshot
|
|
@@ -186,7 +186,7 @@ class SemanticClient:
|
|
|
186
186
|
self._log_bucket: Optional[_TokenBucket] = None
|
|
187
187
|
#: Records dropped locally for being over budget or over a limit.
|
|
188
188
|
self.logs_dropped = 0
|
|
189
|
-
self.subscribe = "
|
|
189
|
+
self.subscribe = "semantic"
|
|
190
190
|
self.closed = False
|
|
191
191
|
|
|
192
192
|
# -- lifecycle ---------------------------------------------------------
|
|
@@ -390,10 +390,9 @@ class SemanticClient:
|
|
|
390
390
|
marker escapes.
|
|
391
391
|
"""
|
|
392
392
|
messages = []
|
|
393
|
-
sent_snapshot =
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
messages.append(snapshot_message(wire))
|
|
393
|
+
sent_snapshot = True
|
|
394
|
+
self._log("io", f"r{wire['revision']} semantic-full nodes={len(wire.get('nodes', ()))}")
|
|
395
|
+
messages.append(semantic_full_message(wire))
|
|
397
396
|
messages.append(revision_commit(wire["revision"]))
|
|
398
397
|
return (
|
|
399
398
|
tuple(encode_frame(message, self._limits.maxFrameBytes) for message in messages),
|
|
@@ -18,11 +18,11 @@ from .logs import LogRecord, validate_log_record
|
|
|
18
18
|
from .roles import CAPABILITY_SET, EVIDENCE_PROVIDER_CAPABILITY_SET
|
|
19
19
|
from .validate import validate_snapshot
|
|
20
20
|
|
|
21
|
-
PROTOCOL_ID = "termwright/
|
|
22
|
-
PROTOCOL_VERSION =
|
|
21
|
+
PROTOCOL_ID = "termwright/3"
|
|
22
|
+
PROTOCOL_VERSION = 3
|
|
23
23
|
|
|
24
24
|
ERROR_CODES = ("bad-token", "bad-version", "malformed", "limit-exceeded", "duplicate-semantic-key", "adapter-guarantee-violation", "internal")
|
|
25
|
-
SUBSCRIBE_MODES = ("
|
|
25
|
+
SUBSCRIBE_MODES = ("semantic",)
|
|
26
26
|
|
|
27
27
|
MAX_IDENTIFIER_LENGTH = 1024
|
|
28
28
|
_MAX_SAFE_INTEGER = 2**53 - 1
|
|
@@ -73,15 +73,19 @@ def hello(
|
|
|
73
73
|
"capabilities": list(capabilities),
|
|
74
74
|
}
|
|
75
75
|
if probe is not None:
|
|
76
|
+
if not isinstance(probe.get("instrumentation"), Mapping):
|
|
77
|
+
raise ProtocolViolation(
|
|
78
|
+
"marker-argument", "probe.instrumentation is required for every probe"
|
|
79
|
+
)
|
|
76
80
|
message["probe"] = dict(probe)
|
|
77
81
|
if providers:
|
|
78
82
|
message["providers"] = [dict(provider) for provider in providers]
|
|
79
83
|
return message
|
|
80
84
|
|
|
81
85
|
|
|
82
|
-
def
|
|
86
|
+
def semantic_full_message(snapshot: Mapping[str, Any]) -> Dict[str, Any]:
|
|
83
87
|
"""Wrap a wire-form snapshot in its envelope."""
|
|
84
|
-
return {"type": "
|
|
88
|
+
return {"type": "semantic-full", "snapshot": dict(snapshot)}
|
|
85
89
|
|
|
86
90
|
|
|
87
91
|
def revision_commit(revision: int) -> Dict[str, Any]:
|
|
@@ -260,6 +264,12 @@ def parse_adapter_message(value: Any, limits: ProtocolLimits = DEFAULT_LIMITS) -
|
|
|
260
264
|
for item in capabilities:
|
|
261
265
|
if item not in CAPABILITY_SET:
|
|
262
266
|
return _malformed(f"capabilities: unknown capability {item!r}")
|
|
267
|
+
if "probe" in message:
|
|
268
|
+
probe = message["probe"]
|
|
269
|
+
if not isinstance(probe, dict):
|
|
270
|
+
return _malformed("probe: expected an object")
|
|
271
|
+
if not isinstance(probe.get("instrumentation"), dict):
|
|
272
|
+
return _malformed("probe.instrumentation: required")
|
|
263
273
|
if "providers" in message:
|
|
264
274
|
providers = message["providers"]
|
|
265
275
|
if not isinstance(providers, list) or len(providers) > 64:
|
|
@@ -295,7 +305,7 @@ def parse_adapter_message(value: Any, limits: ProtocolLimits = DEFAULT_LIMITS) -
|
|
|
295
305
|
issue = _exact_keys(message, ("type", "revision")) or _revision(message.get("revision"), "revision")
|
|
296
306
|
return _malformed(issue) if issue else ParseResult(ok=True, message=message)
|
|
297
307
|
|
|
298
|
-
if kind == "
|
|
308
|
+
if kind == "semantic-full":
|
|
299
309
|
issue = _exact_keys(message, ("type", "snapshot"))
|
|
300
310
|
if issue:
|
|
301
311
|
return _malformed(issue)
|
|
@@ -368,7 +378,7 @@ def parse_driver_message(value: Any, limits: ProtocolLimits = DEFAULT_LIMITS) ->
|
|
|
368
378
|
if issue:
|
|
369
379
|
return _malformed(issue)
|
|
370
380
|
if message["subscribe"] not in SUBSCRIBE_MODES:
|
|
371
|
-
return _malformed("subscribe: expected '
|
|
381
|
+
return _malformed("subscribe: expected 'semantic'")
|
|
372
382
|
marker = message["marker"]
|
|
373
383
|
if not isinstance(marker, dict):
|
|
374
384
|
return _malformed("marker: expected an object")
|
|
@@ -383,6 +393,24 @@ def parse_driver_message(value: Any, limits: ProtocolLimits = DEFAULT_LIMITS) ->
|
|
|
383
393
|
return _malformed(issue)
|
|
384
394
|
return ParseResult(ok=True, message=message)
|
|
385
395
|
|
|
396
|
+
if kind == "semantic-resync-request":
|
|
397
|
+
issue = _required_keys(
|
|
398
|
+
message, ("type", "sessionId", "expectedBaseRevision", "reason")
|
|
399
|
+
)
|
|
400
|
+
if issue:
|
|
401
|
+
return _malformed(issue)
|
|
402
|
+
issue = _identifier(message["sessionId"], "sessionId")
|
|
403
|
+
if issue:
|
|
404
|
+
return _malformed(issue)
|
|
405
|
+
expected = message["expectedBaseRevision"]
|
|
406
|
+
if expected is not None:
|
|
407
|
+
issue = _revision(expected, "expectedBaseRevision")
|
|
408
|
+
if issue:
|
|
409
|
+
return _malformed(issue)
|
|
410
|
+
if message["reason"] not in ("base-mismatch", "missing-base", "driver-reset"):
|
|
411
|
+
return _malformed("reason: unknown semantic resync reason")
|
|
412
|
+
return ParseResult(ok=True, message=message)
|
|
413
|
+
|
|
386
414
|
if kind == "error":
|
|
387
415
|
issue = _check_error(message, strict=False)
|
|
388
416
|
return _malformed(issue) if issue else ParseResult(ok=True, message=message)
|
|
@@ -307,7 +307,7 @@ class SemanticSnapshot:
|
|
|
307
307
|
rootIds: Sequence[str] = field(default_factory=list)
|
|
308
308
|
nodes: Sequence[SemanticNode] = field(default_factory=list)
|
|
309
309
|
cursor: Optional[CursorInfo] = None
|
|
310
|
-
v: int =
|
|
310
|
+
v: int = 3
|
|
311
311
|
|
|
312
312
|
def to_wire(self) -> Dict[str, Any]:
|
|
313
313
|
wire: Dict[str, Any] = {
|
|
@@ -572,8 +572,8 @@ def _snapshot_schema(value: Any, limits: ProtocolLimits) -> None:
|
|
|
572
572
|
version = snapshot.get("v")
|
|
573
573
|
_strict(snapshot, _SNAPSHOT_KEYS, ())
|
|
574
574
|
|
|
575
|
-
if version !=
|
|
576
|
-
raise _Issue(("v",), "expected the literal
|
|
575
|
+
if version != 3:
|
|
576
|
+
raise _Issue(("v",), "expected the literal 3")
|
|
577
577
|
if "sessionId" not in snapshot:
|
|
578
578
|
raise _Issue(("sessionId",), "expected a string")
|
|
579
579
|
if _text(snapshot["sessionId"], ("sessionId",), limits) == "":
|
|
@@ -506,7 +506,7 @@ def build_snapshot(
|
|
|
506
506
|
rows=rows,
|
|
507
507
|
rootIds=root_ids,
|
|
508
508
|
nodes=nodes,
|
|
509
|
-
v=
|
|
509
|
+
v=3,
|
|
510
510
|
coordinateSpace=WireObservation(status="known", value="viewport-cells", evidence=framework_evidence("textual-probe")),
|
|
511
511
|
hitGrid=WireObservation(status="known", value={"regions": hit_regions}, evidence=framework_evidence("textual-compositor-hit-grid")),
|
|
512
512
|
)
|
|
@@ -29,7 +29,7 @@ def load_vectors(name: str) -> Dict[str, Any]:
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def geometry(rect: Rect = Rect(0, 0, 1, 1)) -> NodeGeometryObservations:
|
|
32
|
-
"""Known viewport geometry for protocol-
|
|
32
|
+
"""Known viewport geometry for protocol-v3 unit fixtures."""
|
|
33
33
|
return NodeGeometryObservations(
|
|
34
34
|
displayed=Observation("known", True, evidence=framework_evidence("python-test")),
|
|
35
35
|
intendedRect=Observation("known", rect, evidence=framework_evidence("python-test")),
|
|
@@ -70,7 +70,7 @@ class FakeDriver:
|
|
|
70
70
|
self,
|
|
71
71
|
path: str,
|
|
72
72
|
logs: Optional[Dict[str, Any]] = None,
|
|
73
|
-
subscribe: str = "
|
|
73
|
+
subscribe: str = "semantic",
|
|
74
74
|
) -> None:
|
|
75
75
|
self.path = path
|
|
76
76
|
self.logs = logs
|
|
@@ -186,7 +186,7 @@ async def test_handshake_and_publish(endpoint):
|
|
|
186
186
|
await driver.wait_for(2)
|
|
187
187
|
|
|
188
188
|
snapshot_frame, commit_frame = driver.received[0], driver.received[1]
|
|
189
|
-
assert snapshot_frame["type"] == "
|
|
189
|
+
assert snapshot_frame["type"] == "semantic-full"
|
|
190
190
|
assert snapshot_frame["snapshot"]["sessionId"] == SESSION
|
|
191
191
|
assert snapshot_frame["snapshot"]["revision"] == 1
|
|
192
192
|
assert commit_frame == {"type": "revision-commit", "revision": 1}
|
|
@@ -282,23 +282,23 @@ async def test_nowait_oversize_has_no_marker_and_recovers():
|
|
|
282
282
|
|
|
283
283
|
decoder = FrameDecoder(limits.maxFrameBytes, limits.maxDepth)
|
|
284
284
|
messages = [message for frame in writer.frames for message in decoder.push(frame)]
|
|
285
|
-
assert [message["type"] for message in messages] == ["
|
|
285
|
+
assert [message["type"] for message in messages] == ["semantic-full", "revision-commit"]
|
|
286
286
|
assert messages[0]["snapshot"]["revision"] == 1
|
|
287
287
|
assert messages[1]["revision"] == 1
|
|
288
288
|
assert client.connected
|
|
289
289
|
|
|
290
290
|
|
|
291
|
-
async def
|
|
292
|
-
driver = FakeDriver(endpoint, subscribe="
|
|
291
|
+
async def test_the_single_semantic_subscription_always_gets_a_full_tree(endpoint):
|
|
292
|
+
driver = FakeDriver(endpoint, subscribe="semantic")
|
|
293
293
|
await driver.start()
|
|
294
294
|
client = SemanticClient(endpoint, TOKEN, adapter_name="pytest", adapter_version="0.1.0")
|
|
295
295
|
assert await client.start(timeout=2.0) is True
|
|
296
296
|
|
|
297
297
|
await client.publish(sample_snapshot())
|
|
298
|
-
await driver.wait_for(
|
|
298
|
+
await driver.wait_for(2)
|
|
299
299
|
|
|
300
300
|
kinds = [frame["type"] for frame in driver.received]
|
|
301
|
-
assert kinds == ["revision-commit"], kinds
|
|
301
|
+
assert kinds == ["semantic-full", "revision-commit"], kinds
|
|
302
302
|
|
|
303
303
|
await client.close()
|
|
304
304
|
await driver.close()
|
|
@@ -363,7 +363,7 @@ async def test_a_write_to_a_stalled_driver_is_bounded(endpoint):
|
|
|
363
363
|
"protocol": PROTOCOL_ID,
|
|
364
364
|
"sessionId": SESSION,
|
|
365
365
|
"limits": DEFAULT_LIMITS.to_wire(),
|
|
366
|
-
"subscribe": "
|
|
366
|
+
"subscribe": "semantic",
|
|
367
367
|
"marker": {"enabled": True},
|
|
368
368
|
}
|
|
369
369
|
writer.write(encode_frame(ack, DEFAULT_LIMITS.maxFrameBytes))
|
|
@@ -22,20 +22,28 @@ def ack(**changes):
|
|
|
22
22
|
"protocol": PROTOCOL_ID,
|
|
23
23
|
"sessionId": "s-1",
|
|
24
24
|
"limits": DEFAULT_LIMITS.to_wire(),
|
|
25
|
-
"subscribe": "
|
|
25
|
+
"subscribe": "semantic",
|
|
26
26
|
"marker": {"enabled": True},
|
|
27
27
|
}
|
|
28
28
|
message.update(changes)
|
|
29
29
|
return message
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def test_protocol_v3_messages_are_accepted():
|
|
33
33
|
tree = snapshot(nodes=[node(id="root", role="application", name="app")], root_ids=["root"])
|
|
34
34
|
messages = [
|
|
35
35
|
(parse_adapter_message, hello("token", "pytest", "0.1.0", ["tree"])),
|
|
36
|
-
(parse_adapter_message, {"type": "
|
|
36
|
+
(parse_adapter_message, {"type": "semantic-full", "snapshot": tree.to_wire()}),
|
|
37
37
|
(parse_driver_message, ack()),
|
|
38
|
-
(
|
|
38
|
+
(
|
|
39
|
+
parse_driver_message,
|
|
40
|
+
{
|
|
41
|
+
"type": "semantic-resync-request",
|
|
42
|
+
"sessionId": "s-1",
|
|
43
|
+
"expectedBaseRevision": None,
|
|
44
|
+
"reason": "driver-reset",
|
|
45
|
+
},
|
|
46
|
+
),
|
|
39
47
|
]
|
|
40
48
|
for parser, message in messages:
|
|
41
49
|
result = parser(message, DEFAULT_LIMITS)
|
|
@@ -148,11 +148,11 @@ async def test_instrumented_output_is_the_same_render_plus_markers(endpoint):
|
|
|
148
148
|
asyncio.to_thread(run_on_pty, env, release)
|
|
149
149
|
)
|
|
150
150
|
while not any(
|
|
151
|
-
message.get("type") == "
|
|
151
|
+
message.get("type") == "semantic-full" for message in driver.received
|
|
152
152
|
):
|
|
153
153
|
driver.frame_arrived.clear()
|
|
154
154
|
if any(
|
|
155
|
-
message.get("type") == "
|
|
155
|
+
message.get("type") == "semantic-full"
|
|
156
156
|
for message in driver.received
|
|
157
157
|
):
|
|
158
158
|
break
|
|
@@ -169,5 +169,5 @@ async def test_instrumented_output_is_the_same_render_plus_markers(endpoint):
|
|
|
169
169
|
"instrumentation changed the render, not just the commits"
|
|
170
170
|
)
|
|
171
171
|
|
|
172
|
-
published = [m for m in driver.received if m.get("type") == "
|
|
172
|
+
published = [m for m in driver.received if m.get("type") == "semantic-full"]
|
|
173
173
|
assert published, "markers were written but no tree was published"
|
|
@@ -173,12 +173,12 @@ async def test_it_publishes_a_valid_tree_for_a_real_app(endpoint):
|
|
|
173
173
|
await wait_for(lambda: client.connected)
|
|
174
174
|
session.on_frame(commit_for(app))
|
|
175
175
|
await wait_for(
|
|
176
|
-
lambda: any(m.get("type") == "
|
|
176
|
+
lambda: any(m.get("type") == "semantic-full" for m in driver.received)
|
|
177
177
|
)
|
|
178
178
|
await pilot.pause()
|
|
179
179
|
await client.close()
|
|
180
180
|
|
|
181
|
-
published = [m for m in driver.received if m.get("type") == "
|
|
181
|
+
published = [m for m in driver.received if m.get("type") == "semantic-full"]
|
|
182
182
|
assert published, "nothing reached the driver"
|
|
183
183
|
snapshot = published[-1]["snapshot"]
|
|
184
184
|
result = validate_snapshot(snapshot, DEFAULT_LIMITS)
|
|
@@ -432,7 +432,7 @@ async def test_a_vanilla_app_in_a_child_process_publishes_a_tree(endpoint, tmp_p
|
|
|
432
432
|
)
|
|
433
433
|
try:
|
|
434
434
|
await wait_for(
|
|
435
|
-
lambda: any(m.get("type") == "
|
|
435
|
+
lambda: any(m.get("type") == "semantic-full" for m in driver.received),
|
|
436
436
|
timeout=30.0,
|
|
437
437
|
)
|
|
438
438
|
finally:
|
|
@@ -440,7 +440,7 @@ async def test_a_vanilla_app_in_a_child_process_publishes_a_tree(endpoint, tmp_p
|
|
|
440
440
|
child.terminate()
|
|
441
441
|
await child.wait()
|
|
442
442
|
|
|
443
|
-
published = [m for m in driver.received if m.get("type") == "
|
|
443
|
+
published = [m for m in driver.received if m.get("type") == "semantic-full"]
|
|
444
444
|
assert published, "the child published nothing"
|
|
445
445
|
snapshot = published[-1]["snapshot"]
|
|
446
446
|
result = validate_snapshot(snapshot, DEFAULT_LIMITS)
|
|
@@ -298,7 +298,7 @@ async def test_publishes_qualified_geometry_and_exact_hit_grid():
|
|
|
298
298
|
async with app.run_test(size=(40, 10)) as pilot:
|
|
299
299
|
await pilot.pause()
|
|
300
300
|
snapshot = build_snapshot(app, app.screen, Identities(), session_id="s", revision=1).to_wire()
|
|
301
|
-
assert snapshot["v"] ==
|
|
301
|
+
assert snapshot["v"] == 3
|
|
302
302
|
assert snapshot["coordinateSpace"]["value"] == "viewport-cells"
|
|
303
303
|
assert snapshot["hitGrid"]["status"] == "known"
|
|
304
304
|
approve = by_test_id(snapshot)["approve"]
|
|
@@ -31,7 +31,7 @@ def test_snapshot_vectors_match_the_reference_validator():
|
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def test_valid_protocol_v3_snapshot_is_accepted():
|
|
35
35
|
value = snapshot(
|
|
36
36
|
nodes=[
|
|
37
37
|
node(id="root", role="dialog", name="Permission", rect=Rect(0, 0, 20, 4)),
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|