onec-interactive-runtime-core 0.1.19__py3-none-any.whl

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.
Files changed (87) hide show
  1. onec_interactive_runtime_core-0.1.19.dist-info/METADATA +12 -0
  2. onec_interactive_runtime_core-0.1.19.dist-info/RECORD +87 -0
  3. onec_interactive_runtime_core-0.1.19.dist-info/WHEEL +4 -0
  4. onec_interactive_runtime_core-0.1.19.dist-info/licenses/COPYRIGHT +9 -0
  5. onec_interactive_runtime_core-0.1.19.dist-info/licenses/LICENSE +232 -0
  6. onec_interactive_runtime_core-0.1.19.dist-info/licenses/THIRD_PARTY_NOTICES.txt +32 -0
  7. onec_runtime/AGENTS.md +7 -0
  8. onec_runtime/__init__.py +3 -0
  9. onec_runtime/artifacts.py +59 -0
  10. onec_runtime/bootstrap.py +310 -0
  11. onec_runtime/breakpoint_workspace.py +249 -0
  12. onec_runtime/bsl/__init__.py +139 -0
  13. onec_runtime/bsl/diagnostics.py +1046 -0
  14. onec_runtime/bsl/full_ast_worker_projection.py +522 -0
  15. onec_runtime/bsl/generated_semantic_parser.py +6322 -0
  16. onec_runtime/bsl/lexer.py +164 -0
  17. onec_runtime/bsl/module_catalog.py +420 -0
  18. onec_runtime/bsl/module_delta.py +1079 -0
  19. onec_runtime/bsl/module_universe.py +1877 -0
  20. onec_runtime/bsl/notebook_cells.py +232 -0
  21. onec_runtime/bsl/notebook_method_globals.py +74 -0
  22. onec_runtime/bsl/notebook_methods.py +175 -0
  23. onec_runtime/bsl/parser_artifact_identity.py +119 -0
  24. onec_runtime/bsl/parser_target.py +388 -0
  25. onec_runtime/bsl/preprocessor.py +16 -0
  26. onec_runtime/bsl/semantic_lowering.py +1539 -0
  27. onec_runtime/bsl/source_maps.py +2411 -0
  28. onec_runtime/bsl/worker_dependency_resolver.py +289 -0
  29. onec_runtime/bsl/worker_preprocessor.py +247 -0
  30. onec_runtime/bsl/worker_projection_model.py +137 -0
  31. onec_runtime/bsl/worker_reload_source_map.py +1697 -0
  32. onec_runtime/capture.py +113 -0
  33. onec_runtime/capture_source.py +453 -0
  34. onec_runtime/compact_table.py +376 -0
  35. onec_runtime/compact_table_backend.py +500 -0
  36. onec_runtime/config.py +198 -0
  37. onec_runtime/configurator_agent.py +520 -0
  38. onec_runtime/controller_worker.py +400 -0
  39. onec_runtime/credentials.py +18 -0
  40. onec_runtime/epf_container.py +196 -0
  41. onec_runtime/errors.py +205 -0
  42. onec_runtime/experiment.py +130 -0
  43. onec_runtime/extension_bundle.py +944 -0
  44. onec_runtime/extension_lifecycle.py +402 -0
  45. onec_runtime/extension_state.py +222 -0
  46. onec_runtime/fault_injection.py +30 -0
  47. onec_runtime/kernel.py +179 -0
  48. onec_runtime/lease.py +123 -0
  49. onec_runtime/observation.py +287 -0
  50. onec_runtime/performance_profile.py +245 -0
  51. onec_runtime/privacy.py +263 -0
  52. onec_runtime/processes.py +265 -0
  53. onec_runtime/prototype_runtime.py +2644 -0
  54. onec_runtime/rdbg/__init__.py +1 -0
  55. onec_runtime/rdbg/models.py +130 -0
  56. onec_runtime/rdbg/reconnect.py +59 -0
  57. onec_runtime/rdbg/session.py +913 -0
  58. onec_runtime/rdbg/transport.py +138 -0
  59. onec_runtime/rdbg/xml_codec.py +980 -0
  60. onec_runtime/recovery.py +106 -0
  61. onec_runtime/recovery_journal.py +79 -0
  62. onec_runtime/resources/extension/OnecInteractiveRuntime.cfe +0 -0
  63. onec_runtime/resources/extension/extension-manifest.json +108 -0
  64. onec_runtime/runtime_api.py +5272 -0
  65. onec_runtime/runtime_contracts.py +196 -0
  66. onec_runtime/server_worker.py +2034 -0
  67. onec_runtime/session.py +2123 -0
  68. onec_runtime/startup_diagnostics.py +45 -0
  69. onec_runtime/stop_routing.py +65 -0
  70. onec_runtime/supervised_processes.py +232 -0
  71. onec_runtime/supervised_runtime.py +512 -0
  72. onec_runtime/supervisor.py +363 -0
  73. onec_runtime/supervisor_model.py +148 -0
  74. onec_runtime/supervisor_protocol.py +77 -0
  75. onec_runtime/table_materialization.py +471 -0
  76. onec_runtime/table_transfer_backend.py +203 -0
  77. onec_runtime/table_value.py +311 -0
  78. onec_runtime/toolchain.py +730 -0
  79. onec_runtime/value_materialization.py +432 -0
  80. onec_runtime/value_transfer_backend.py +199 -0
  81. onec_runtime/worker_breakpoints.py +1431 -0
  82. onec_runtime/worker_epf.py +313 -0
  83. onec_runtime/worker_epf_template.py +53 -0
  84. onec_runtime/worker_stage_protocol.py +516 -0
  85. onec_runtime/worker_universe.py +3772 -0
  86. onec_runtime_build/__init__.py +1 -0
  87. onec_runtime_build/parser_target_development.py +116 -0
@@ -0,0 +1,310 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import asdict, dataclass
5
+ from time import monotonic
6
+ from typing import Protocol
7
+ from uuid import UUID
8
+
9
+ from onec_runtime.errors import (
10
+ CommandTimeout,
11
+ ExtensionHandshakeError,
12
+ ProtocolError,
13
+ UnexpectedStop,
14
+ )
15
+ from onec_runtime.extension_bundle import EXTENSION_NAME, ExtensionHandshakeEvidence
16
+ from onec_runtime.kernel import SESSION_MODULE_PROPERTY_ID
17
+ from onec_runtime.rdbg.models import (
18
+ DebugTarget,
19
+ EvaluationResult,
20
+ ModifyResult,
21
+ ModuleLocation,
22
+ StopEvent,
23
+ )
24
+
25
+
26
+ class BootstrapSession(Protocol):
27
+ break_on_next: bool
28
+
29
+ def wait_for_any_stop(
30
+ self,
31
+ *,
32
+ timeout_s: float,
33
+ on_poll: Callable[[], None] | None = None,
34
+ ) -> StopEvent: ...
35
+
36
+ def continue_(self) -> None: ...
37
+
38
+
39
+ class ServerBootstrapSession(Protocol):
40
+ expected_location: ModuleLocation
41
+ target: DebugTarget | None
42
+
43
+ def set_service_breakpoint(self) -> None: ...
44
+
45
+ def continue_(self) -> None: ...
46
+
47
+ def wait_for_service_stop(self, *, timeout_s: float) -> StopEvent: ...
48
+
49
+
50
+ class ServerGuardSession(Protocol):
51
+ def evaluate(self, expression: str) -> EvaluationResult: ...
52
+
53
+ def modify(self, variable: str, value_expression: str) -> ModifyResult: ...
54
+
55
+
56
+ @dataclass(frozen=True, slots=True)
57
+ class ExtensionHandshakeContract:
58
+ product_id: str
59
+ artifact_version: str
60
+ protocol_version: str
61
+
62
+
63
+ _HANDSHAKE_EXPRESSIONS = (
64
+ ("product_id", "ИдентификаторПродуктаRuntime"),
65
+ ("artifact_version", "ВерсияАртефактаRuntime"),
66
+ ("protocol_version", "ВерсияПротоколаRuntime"),
67
+ )
68
+ _MAX_HANDSHAKE_VALUE_LENGTH = 128
69
+
70
+
71
+ def _handshake_string(result: EvaluationResult, variable: str) -> str:
72
+ if result.error_occurred:
73
+ raise ExtensionHandshakeError(
74
+ f"Extension handshake evaluation failed for {variable}"
75
+ )
76
+ if result.type_name != "Строка":
77
+ raise ExtensionHandshakeError(
78
+ f"Extension handshake variable {variable} is not a string"
79
+ )
80
+ presentation = result.presentation
81
+ if (
82
+ not presentation
83
+ or len(presentation) > _MAX_HANDSHAKE_VALUE_LENGTH
84
+ or any(ord(character) < 32 for character in presentation)
85
+ ):
86
+ raise ExtensionHandshakeError(
87
+ f"Extension handshake variable {variable} has an unsafe value"
88
+ )
89
+ if presentation.startswith('"') or presentation.endswith('"'):
90
+ if not (presentation.startswith('"') and presentation.endswith('"')):
91
+ raise ExtensionHandshakeError(
92
+ f"Extension handshake variable {variable} has an invalid presentation"
93
+ )
94
+ inner = presentation[1:-1]
95
+ if '"' in inner.replace('""', ""):
96
+ raise ExtensionHandshakeError(
97
+ f"Extension handshake variable {variable} has an invalid presentation"
98
+ )
99
+ presentation = inner.replace('""', '"')
100
+ if not presentation:
101
+ raise ExtensionHandshakeError(
102
+ f"Extension handshake variable {variable} has an empty value"
103
+ )
104
+ if len(presentation) > _MAX_HANDSHAKE_VALUE_LENGTH:
105
+ raise ExtensionHandshakeError(
106
+ f"Extension handshake variable {variable} has an unsafe value"
107
+ )
108
+ return presentation
109
+
110
+
111
+ def observe_extension_handshake(
112
+ session: ServerGuardSession,
113
+ *,
114
+ target_type: str,
115
+ location: ModuleLocation,
116
+ ) -> ExtensionHandshakeEvidence:
117
+ values = {
118
+ field: _handshake_string(session.evaluate(variable), variable)
119
+ for field, variable in _HANDSHAKE_EXPRESSIONS
120
+ }
121
+ return ExtensionHandshakeEvidence(
122
+ target_type=target_type,
123
+ product_id=values["product_id"],
124
+ artifact_version=values["artifact_version"],
125
+ protocol_version=values["protocol_version"],
126
+ location=location,
127
+ )
128
+
129
+
130
+ def verify_extension_handshake(
131
+ session: ServerGuardSession,
132
+ contract: ExtensionHandshakeContract,
133
+ *,
134
+ target_type: str,
135
+ location: ModuleLocation,
136
+ ) -> ExtensionHandshakeEvidence:
137
+ evidence = observe_extension_handshake(
138
+ session,
139
+ target_type=target_type,
140
+ location=location,
141
+ )
142
+ expected = (
143
+ ("ИдентификаторПродуктаRuntime", evidence.product_id, contract.product_id),
144
+ ("ВерсияАртефактаRuntime", evidence.artifact_version, contract.artifact_version),
145
+ ("ВерсияПротоколаRuntime", evidence.protocol_version, contract.protocol_version),
146
+ )
147
+ for variable, actual, required in expected:
148
+ if actual != required:
149
+ raise ExtensionHandshakeError(
150
+ f"Extension handshake mismatch for {variable}"
151
+ )
152
+ return evidence
153
+
154
+
155
+ def verify_extension_safe_mode_disabled(session: ServerGuardSession) -> None:
156
+ """Verify the installed extension property in the live server infobase."""
157
+ expression = (
158
+ 'РасширенияКонфигурации.Получить(Новый Структура("Имя", '
159
+ f'"{EXTENSION_NAME}"))[0].БезопасныйРежим'
160
+ )
161
+ result = session.evaluate(expression)
162
+ if (
163
+ result.error_occurred
164
+ or result.type_name not in {"Булево", "Boolean"}
165
+ or result.presentation not in {"Ложь", "False"}
166
+ ):
167
+ raise ExtensionHandshakeError(
168
+ "Runtime extension safe mode is enabled or could not be verified"
169
+ )
170
+
171
+
172
+ @dataclass(frozen=True)
173
+ class GuardValueEvidence:
174
+ type_name: str
175
+ presentation: str
176
+ error_occurred: bool
177
+
178
+
179
+ @dataclass(frozen=True)
180
+ class ServerLoopGuardEvidence:
181
+ variable: str
182
+ before: GuardValueEvidence
183
+ write: GuardValueEvidence
184
+ after: GuardValueEvidence
185
+
186
+ def as_dict(self) -> dict[str, object]:
187
+ return {
188
+ "variable": self.variable,
189
+ "before": asdict(self.before),
190
+ "write": {"expression": "Истина", **asdict(self.write)},
191
+ "after": asdict(self.after),
192
+ }
193
+
194
+
195
+ def _guard_value(result: EvaluationResult | ModifyResult) -> GuardValueEvidence:
196
+ return GuardValueEvidence(
197
+ type_name=result.type_name,
198
+ presentation=result.presentation,
199
+ error_occurred=result.error_occurred,
200
+ )
201
+
202
+
203
+ def _is_boolean(result: EvaluationResult | ModifyResult, presentation: str) -> bool:
204
+ return (
205
+ not result.error_occurred
206
+ and result.type_name == "Булево"
207
+ and result.presentation == presentation
208
+ )
209
+
210
+
211
+ def enable_server_kernel_loop(
212
+ session: ServerGuardSession,
213
+ ) -> ServerLoopGuardEvidence:
214
+ variable = "ПродолжатьЦикл"
215
+ before = session.evaluate(variable)
216
+ if not _is_boolean(before, "Ложь"):
217
+ raise ProtocolError("Server KernelLoop guard was not Ложь before bootstrap")
218
+ write = session.modify(variable, "Истина")
219
+ if not _is_boolean(write, "Истина"):
220
+ detail = f": {write.error_text}" if write.error_text else ""
221
+ raise ProtocolError(f"Unable to enable server KernelLoop guard{detail}")
222
+ after = session.evaluate(variable)
223
+ if not _is_boolean(after, "Истина"):
224
+ raise ProtocolError("Server KernelLoop guard readback was not Истина")
225
+ return ServerLoopGuardEvidence(
226
+ variable=variable,
227
+ before=_guard_value(before),
228
+ write=_guard_value(write),
229
+ after=_guard_value(after),
230
+ )
231
+
232
+
233
+ def _is_known_break_on_next_transient(
234
+ session: BootstrapSession,
235
+ location: ModuleLocation,
236
+ expected: ModuleLocation,
237
+ ) -> bool:
238
+ if not session.break_on_next:
239
+ return False
240
+ return bool(
241
+ (
242
+ location.module_type == "ConfigModule"
243
+ and location.property_id == UUID(SESSION_MODULE_PROPERTY_ID)
244
+ and location.line > 0
245
+ )
246
+ or (
247
+ location.module_type == expected.module_type
248
+ and location.url == expected.url
249
+ and location.object_id == expected.object_id
250
+ and location.property_id == expected.property_id
251
+ and location.extension_name == expected.extension_name
252
+ and location.ext_id == expected.ext_id
253
+ and 0 < location.line < expected.line
254
+ )
255
+ )
256
+
257
+
258
+ def wait_for_managed_startup_stop(
259
+ session: BootstrapSession,
260
+ expected: ModuleLocation,
261
+ *,
262
+ timeout_s: float,
263
+ on_poll: Callable[[], None] | None = None,
264
+ ) -> StopEvent:
265
+ deadline = monotonic() + timeout_s
266
+ while monotonic() < deadline:
267
+ remaining = max(0.1, deadline - monotonic())
268
+ if on_poll is None:
269
+ stop = session.wait_for_any_stop(timeout_s=remaining)
270
+ else:
271
+ stop = session.wait_for_any_stop(timeout_s=remaining, on_poll=on_poll)
272
+ if stop.location == expected:
273
+ return stop
274
+ if _is_known_break_on_next_transient(session, stop.location, expected):
275
+ session.continue_()
276
+ continue
277
+ raise UnexpectedStop(f"Unexpected managed bootstrap stop: {stop.location!r}")
278
+ raise CommandTimeout("Timed out waiting for managed startup breakpoint")
279
+
280
+
281
+ def wait_for_server_entry_then_service(
282
+ session: ServerBootstrapSession,
283
+ entry_location: ModuleLocation,
284
+ service_location: ModuleLocation,
285
+ *,
286
+ timeout_s: float,
287
+ on_entry: Callable[[ServerBootstrapSession], None] | None = None,
288
+ server_target_type: str = "ServerEmulation",
289
+ ) -> tuple[StopEvent, StopEvent]:
290
+ deadline = monotonic() + timeout_s
291
+
292
+ def remaining() -> float:
293
+ return max(0.1, deadline - monotonic())
294
+
295
+ session.expected_location = entry_location
296
+ session.set_service_breakpoint()
297
+ session.continue_()
298
+ entry_stop = session.wait_for_service_stop(timeout_s=remaining())
299
+ if session.target is None or session.target.target_type != server_target_type:
300
+ raise ProtocolError(f"Runtime server entry did not stop on {server_target_type}")
301
+ if on_entry is not None:
302
+ on_entry(session)
303
+
304
+ session.expected_location = service_location
305
+ session.set_service_breakpoint()
306
+ session.continue_()
307
+ service_stop = session.wait_for_service_stop(timeout_s=remaining())
308
+ if session.target is None or session.target.target_type != server_target_type:
309
+ raise ProtocolError(f"Runtime service loop did not stop on {server_target_type}")
310
+ return entry_stop, service_stop
@@ -0,0 +1,249 @@
1
+ """Single-owner, full-replacement RDBG breakpoint workspace."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from hashlib import sha256
7
+ import json
8
+ from threading import RLock
9
+ from typing import Protocol
10
+
11
+ from onec_runtime.errors import ProtocolError
12
+ from onec_runtime.rdbg.models import ModuleLocation
13
+
14
+
15
+ class BreakpointWorkspaceOutcomeUnknown(ProtocolError):
16
+ """The debugger may have applied a workspace whose receipt was not observed."""
17
+
18
+
19
+ class _BreakpointSession(Protocol):
20
+ def set_breakpoints(self, locations: tuple[ModuleLocation, ...]) -> None: ...
21
+
22
+
23
+ def _location_key(location: ModuleLocation) -> tuple[object, ...]:
24
+ return (
25
+ location.module_type,
26
+ location.url,
27
+ location.object_id.hex,
28
+ location.property_id.hex,
29
+ location.line,
30
+ location.extension_name,
31
+ location.ext_id,
32
+ )
33
+
34
+
35
+ def _location_payload(location: ModuleLocation) -> dict[str, object]:
36
+ return {
37
+ "module_type": location.module_type,
38
+ "url": location.url,
39
+ "object_id": str(location.object_id),
40
+ "property_id": str(location.property_id),
41
+ "line": location.line,
42
+ "extension_name": location.extension_name,
43
+ "ext_id": location.ext_id,
44
+ }
45
+
46
+
47
+ def _validate_locations(
48
+ value: tuple[ModuleLocation, ...],
49
+ group: str,
50
+ ) -> None:
51
+ if (
52
+ type(value) is not tuple
53
+ or any(type(location) is not ModuleLocation for location in value)
54
+ or len(set(value)) != len(value)
55
+ ):
56
+ raise ValueError(f"{group} breakpoint locations are invalid")
57
+
58
+
59
+ @dataclass(frozen=True, slots=True, repr=False)
60
+ class WorkspaceSnapshot:
61
+ version: int
62
+ service: ModuleLocation
63
+ captures: tuple[ModuleLocation, ...]
64
+ ordinary_users: tuple[ModuleLocation, ...]
65
+ worker_slots: tuple[ModuleLocation, ...]
66
+ shielded: bool
67
+
68
+ def __post_init__(self) -> None:
69
+ if type(self.version) is not int or self.version < 0:
70
+ raise ValueError("breakpoint workspace version is invalid")
71
+ if type(self.service) is not ModuleLocation:
72
+ raise ValueError("breakpoint workspace service location is invalid")
73
+ _validate_locations(self.captures, "capture")
74
+ _validate_locations(self.ordinary_users, "ordinary user")
75
+ _validate_locations(self.worker_slots, "Worker")
76
+ if type(self.shielded) is not bool:
77
+ raise ValueError("breakpoint workspace shield is invalid")
78
+ groups = (
79
+ {self.service},
80
+ set(self.captures),
81
+ set(self.ordinary_users),
82
+ set(self.worker_slots),
83
+ )
84
+ for left_index, left in enumerate(groups):
85
+ for right in groups[left_index + 1 :]:
86
+ if left & right:
87
+ raise ProtocolError("Breakpoint workspace groups overlap")
88
+
89
+ @property
90
+ def effective_locations(self) -> tuple[ModuleLocation, ...]:
91
+ return (
92
+ (self.service,)
93
+ + (() if self.shielded else self.captures)
94
+ + self.ordinary_users
95
+ + self.worker_slots
96
+ )
97
+
98
+ @property
99
+ def digest(self) -> str:
100
+ payload = json.dumps(
101
+ [_location_payload(item) for item in self.effective_locations],
102
+ ensure_ascii=False,
103
+ sort_keys=True,
104
+ separators=(",", ":"),
105
+ ).encode("utf-8")
106
+ return sha256(payload).hexdigest()
107
+
108
+ def __repr__(self) -> str:
109
+ return (
110
+ "WorkspaceSnapshot("
111
+ f"version={self.version}, service=<redacted>, "
112
+ f"captures={len(self.captures)}, "
113
+ f"ordinary_users={len(self.ordinary_users)}, "
114
+ f"worker_slots={len(self.worker_slots)}, "
115
+ f"shielded={self.shielded}, digest={self.digest!r})"
116
+ )
117
+
118
+
119
+ @dataclass(frozen=True, slots=True)
120
+ class WorkspaceInstallReceipt:
121
+ version: int
122
+ requested_digest: str
123
+
124
+ def __post_init__(self) -> None:
125
+ if (
126
+ type(self.version) is not int
127
+ or self.version < 0
128
+ or type(self.requested_digest) is not str
129
+ or len(self.requested_digest) != 64
130
+ ):
131
+ raise ValueError("breakpoint workspace receipt is invalid")
132
+
133
+
134
+ class BreakpointWorkspaceController:
135
+ """Serialize complete debugger workspace replacements and their evidence."""
136
+
137
+ __slots__ = (
138
+ "_confirmed",
139
+ "_lock",
140
+ "_prepared",
141
+ "_session",
142
+ "_unknown",
143
+ )
144
+
145
+ def __init__(
146
+ self,
147
+ session: _BreakpointSession,
148
+ initial: WorkspaceSnapshot,
149
+ ) -> None:
150
+ if type(initial) is not WorkspaceSnapshot:
151
+ raise TypeError("initial breakpoint workspace is required")
152
+ self._session = session
153
+ self._confirmed = initial
154
+ self._unknown = False
155
+ self._prepared: dict[int, WorkspaceSnapshot] = {}
156
+ self._lock = RLock()
157
+
158
+ @property
159
+ def confirmed_snapshot(self) -> WorkspaceSnapshot:
160
+ with self._lock:
161
+ return self._confirmed
162
+
163
+ def prepare(
164
+ self,
165
+ *,
166
+ captures: tuple[ModuleLocation, ...],
167
+ ordinary_users: tuple[ModuleLocation, ...],
168
+ worker_slots: tuple[ModuleLocation, ...],
169
+ shielded: bool,
170
+ ) -> WorkspaceSnapshot:
171
+ if (
172
+ type(worker_slots) is not tuple
173
+ or any(type(item) is not ModuleLocation for item in worker_slots)
174
+ ):
175
+ raise ValueError("Worker breakpoint locations are invalid")
176
+ unique_worker_slots = tuple(sorted(set(worker_slots), key=_location_key))
177
+ with self._lock:
178
+ self.require_confirmed()
179
+ snapshot = WorkspaceSnapshot(
180
+ self._confirmed.version + 1,
181
+ self._confirmed.service,
182
+ captures,
183
+ ordinary_users,
184
+ unique_worker_slots,
185
+ shielded,
186
+ )
187
+ self._prepared[id(snapshot)] = snapshot
188
+ return snapshot
189
+
190
+ def install(self, snapshot: WorkspaceSnapshot) -> WorkspaceInstallReceipt:
191
+ if type(snapshot) is not WorkspaceSnapshot:
192
+ raise TypeError("breakpoint workspace snapshot is required")
193
+ with self._lock:
194
+ self.require_confirmed()
195
+ if (
196
+ self._prepared.get(id(snapshot)) is not snapshot
197
+ or snapshot.version != self._confirmed.version + 1
198
+ ):
199
+ raise ProtocolError("Breakpoint workspace proposal is stale or foreign")
200
+ del self._prepared[id(snapshot)]
201
+ if snapshot.effective_locations != self._confirmed.effective_locations:
202
+ setter = getattr(self._session, "set_breakpoints", None)
203
+ if not callable(setter):
204
+ raise ProtocolError("Breakpoint workspace session is unavailable")
205
+ try:
206
+ setter(snapshot.effective_locations)
207
+ except BaseException as error:
208
+ self._unknown = True
209
+ self._prepared.clear()
210
+ raise BreakpointWorkspaceOutcomeUnknown(
211
+ "Worker breakpoint workspace outcome is unknown"
212
+ ) from error
213
+ self._confirmed = snapshot
214
+ self._prepared = {
215
+ key: value
216
+ for key, value in self._prepared.items()
217
+ if value.version > snapshot.version
218
+ }
219
+ return WorkspaceInstallReceipt(snapshot.version, snapshot.digest)
220
+
221
+ def require_confirmed(self) -> None:
222
+ with self._lock:
223
+ if self._unknown:
224
+ raise BreakpointWorkspaceOutcomeUnknown(
225
+ "Worker breakpoint workspace outcome is unknown"
226
+ )
227
+
228
+ def quarantine(self) -> None:
229
+ with self._lock:
230
+ self._unknown = True
231
+ self._prepared.clear()
232
+
233
+ def _adopt_confirmed_session(
234
+ self,
235
+ session: _BreakpointSession,
236
+ effective_locations: tuple[ModuleLocation, ...],
237
+ ) -> None:
238
+ """Bind a recovered session after it replayed the exact confirmed workspace."""
239
+ with self._lock:
240
+ if not callable(getattr(session, "set_breakpoints", None)):
241
+ raise TypeError("breakpoint workspace session is invalid")
242
+ if (
243
+ type(effective_locations) is not tuple
244
+ or effective_locations != self._confirmed.effective_locations
245
+ ):
246
+ raise ProtocolError("Recovered breakpoint workspace does not match")
247
+ self._session = session
248
+ self._unknown = False
249
+ self._prepared.clear()
@@ -0,0 +1,139 @@
1
+ """Minimal Python lexer/parser target used by the BSL grammar spike."""
2
+
3
+ from onec_runtime.bsl.diagnostics import (
4
+ DiagnosticCoordinateSpace,
5
+ DiagnosticStage,
6
+ LoweredSourceLocation,
7
+ MappingConfidence,
8
+ NormalizedDiagnostic,
9
+ ParsedPlatformDiagnostic,
10
+ PlatformCoordinateCodec,
11
+ VisibleSourceContext,
12
+ VisibleSourceLocation,
13
+ normalize_source_error,
14
+ parse_platform_diagnostic,
15
+ remap_platform_diagnostic,
16
+ )
17
+ from onec_runtime.bsl.preprocessor import preprocess_server_source
18
+ from onec_runtime.bsl.semantic_lowering import (
19
+ LoweringMode,
20
+ MethodScope,
21
+ ModuleBinding,
22
+ NameBinding,
23
+ SemanticLoweringError,
24
+ SemanticLoweringResult,
25
+ SemanticNotebookLowerer,
26
+ SourceEdit,
27
+ WorkerExport,
28
+ )
29
+ from onec_runtime.bsl.source_maps import (
30
+ LineIndex,
31
+ MappedSource,
32
+ MappingRelation,
33
+ SourceArtifactKind,
34
+ SourceArtifactRef,
35
+ SourceMap,
36
+ SourceSpan,
37
+ SourceTransformBuilder,
38
+ SourceUnitKind,
39
+ SourceUnitRef,
40
+ mapped_visible_source,
41
+ source_sha256,
42
+ )
43
+ from onec_runtime.bsl.worker_projection_model import (
44
+ BareName,
45
+ BareNameKind,
46
+ ParsedMethodModel,
47
+ ParsedModuleModel,
48
+ )
49
+
50
+ __all__ = [
51
+ "DiagnosticCoordinateSpace",
52
+ "DiagnosticStage",
53
+ "LoweredSourceLocation",
54
+ "LoweringMode",
55
+ "MappingConfidence",
56
+ "MethodScope",
57
+ "ModuleUniverseAdmissionError",
58
+ "ModuleBinding",
59
+ "NameBinding",
60
+ "NormalizedDiagnostic",
61
+ "ParsedPlatformDiagnostic",
62
+ "PlatformCoordinateCodec",
63
+ "BareName",
64
+ "BareNameKind",
65
+ "ParsedMethodModel",
66
+ "ParsedModuleModel",
67
+ "SemanticLoweringError",
68
+ "SemanticLoweringResult",
69
+ "SemanticNotebookLowerer",
70
+ "SourceEdit",
71
+ "WorkerExport",
72
+ "WorkerModuleUnit",
73
+ "VisibleSourceContext",
74
+ "VisibleSourceLocation",
75
+ "normalize_source_error",
76
+ "parse_platform_diagnostic",
77
+ "remap_platform_diagnostic",
78
+ "preprocess_server_source",
79
+ "CommonModuleCatalogSnapshot",
80
+ "CommonModuleDescriptor",
81
+ "CommonModuleScope",
82
+ "SessionCommonModuleCatalog",
83
+ "LineIndex",
84
+ "MappedSource",
85
+ "MappingRelation",
86
+ "SourceArtifactKind",
87
+ "SourceArtifactRef",
88
+ "SourceMap",
89
+ "SourceSpan",
90
+ "SourceTransformBuilder",
91
+ "SourceUnitKind",
92
+ "SourceUnitRef",
93
+ "mapped_visible_source",
94
+ "source_sha256",
95
+ "MODULE_SCOPE_DEPENDENCY",
96
+ "ResolvedMethodPlan",
97
+ "ResolvedModulePlan",
98
+ "resolve_worker_dependencies",
99
+ "worker_model_candidate_names",
100
+ ]
101
+
102
+
103
+ def __getattr__(name: str) -> object:
104
+ if name not in {
105
+ "CommonModuleCatalogSnapshot",
106
+ "CommonModuleDescriptor",
107
+ "CommonModuleScope",
108
+ "ModuleUniverseAdmissionError",
109
+ "SessionCommonModuleCatalog",
110
+ "WorkerModuleUnit",
111
+ "MODULE_SCOPE_DEPENDENCY",
112
+ "ResolvedMethodPlan",
113
+ "ResolvedModulePlan",
114
+ "resolve_worker_dependencies",
115
+ "worker_model_candidate_names",
116
+ }:
117
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
118
+ if name in {
119
+ "CommonModuleCatalogSnapshot",
120
+ "CommonModuleDescriptor",
121
+ "CommonModuleScope",
122
+ "SessionCommonModuleCatalog",
123
+ }:
124
+ from onec_runtime.bsl import module_catalog
125
+
126
+ return getattr(module_catalog, name)
127
+ if name in {
128
+ "MODULE_SCOPE_DEPENDENCY",
129
+ "ResolvedMethodPlan",
130
+ "ResolvedModulePlan",
131
+ "resolve_worker_dependencies",
132
+ "worker_model_candidate_names",
133
+ }:
134
+ from onec_runtime.bsl import worker_dependency_resolver
135
+
136
+ return getattr(worker_dependency_resolver, name)
137
+ from onec_runtime.bsl import module_universe
138
+
139
+ return getattr(module_universe, name)