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
onec_runtime/errors.py ADDED
@@ -0,0 +1,205 @@
1
+ from __future__ import annotations
2
+
3
+ from onec_runtime.bsl.diagnostics import NormalizedDiagnostic
4
+
5
+
6
+ class RuntimeProbeError(Exception):
7
+ """Base class for runtime probe failures."""
8
+
9
+
10
+ class ModuleUniverseAdmissionError(RuntimeProbeError):
11
+ """A module or common-module catalog entry is not safe to admit."""
12
+
13
+
14
+ class ExtensionBundleError(RuntimeProbeError):
15
+ """The packaged runtime extension contract is malformed or corrupt."""
16
+
17
+
18
+ class ExtensionIdentityConflict(RuntimeProbeError):
19
+ """A named installed extension does not belong to this product."""
20
+
21
+
22
+ class ExtensionLifecycleError(RuntimeProbeError):
23
+ """Automatic runtime extension preparation failed closed."""
24
+
25
+
26
+ class ExtensionLockTimeout(ExtensionLifecycleError):
27
+ """Another process held the target extension lifecycle lock too long."""
28
+
29
+
30
+ class ProcessStartError(RuntimeProbeError):
31
+ """A required local process failed to start or produce its output."""
32
+
33
+
34
+ class ExtensionNotInstalled(RuntimeProbeError):
35
+ """The fixed product extension name is absent from the target infobase."""
36
+
37
+
38
+ class ProtocolError(RuntimeProbeError):
39
+ """The RDBG peer returned an invalid or unsuccessful response."""
40
+
41
+
42
+ class RdbgDebugUiNotRegistered(ProtocolError):
43
+ """The shared debugger no longer recognizes this session's UI identity."""
44
+
45
+
46
+ class PoisonedRuntimeError(ProtocolError):
47
+ """An acknowledged target mutation left host/runtime state unusable."""
48
+
49
+
50
+ class WorkerPromotionOutcomeUnknown(ProtocolError):
51
+ """The target may have swapped Worker generation without acknowledgement."""
52
+
53
+ __slots__ = ("generation", "manifest_sha256")
54
+
55
+ def __init__(self, generation: int, manifest_sha256: str) -> None:
56
+ if (
57
+ type(generation) is not int
58
+ or generation <= 0
59
+ or not isinstance(manifest_sha256, str)
60
+ or len(manifest_sha256) != 64
61
+ or any(
62
+ character not in "0123456789abcdef"
63
+ for character in manifest_sha256
64
+ )
65
+ ):
66
+ raise ValueError("worker promotion outcome identity is invalid")
67
+ self.generation = generation
68
+ self.manifest_sha256 = manifest_sha256
69
+ super().__init__(
70
+ "Worker promotion outcome is unknown "
71
+ f"(generation={generation}, manifest_sha256={manifest_sha256})"
72
+ )
73
+
74
+
75
+ class CaptureSourceNotConfigured(ProtocolError):
76
+ """Symbolic capture requires a matching exported configuration source."""
77
+
78
+
79
+ class ExtensionHandshakeError(ProtocolError):
80
+ """A live extension frame did not match the packaged runtime contract."""
81
+
82
+
83
+ class ManualExtensionUnavailable(ProtocolError):
84
+ """A user-managed runtime extension did not expose its required bootstrap ABI."""
85
+
86
+
87
+ class ManualExtensionVersionWarning(RuntimeWarning):
88
+ """The user-managed extension version differs from the packaged release."""
89
+
90
+
91
+ class MaterializationError(ProtocolError):
92
+ """A 1C value could not be converted into a lossless Python snapshot."""
93
+
94
+
95
+ class UnsupportedOnecType(MaterializationError):
96
+ """The value type has no explicitly registered materialization adapter."""
97
+
98
+
99
+ class MaterializationCycleError(MaterializationError):
100
+ """Recursive 1C containers form a cycle that cannot be snapshotted."""
101
+
102
+
103
+ class MaterializationLimitError(MaterializationError):
104
+ """A configured materialization depth, item, or byte limit was exceeded."""
105
+
106
+
107
+ class MaterializationKeyError(MaterializationError):
108
+ """A 1C Map key cannot be represented losslessly by a Python dict."""
109
+
110
+
111
+ class ValuePayloadError(MaterializationError):
112
+ """A typed value payload is malformed or violates its wire contract."""
113
+
114
+
115
+ class StaleWorkerGeneration(ProtocolError):
116
+ """The supplied worker handle no longer names the active module."""
117
+
118
+
119
+ class UnexpectedStop(RuntimeProbeError):
120
+ """The debug target stopped outside the service breakpoint."""
121
+
122
+
123
+ class CommandTimeout(RuntimeProbeError):
124
+ """A command did not complete by its monotonic deadline."""
125
+
126
+
127
+ class BslExecutionError(RuntimeProbeError):
128
+ """The kernel captured a BSL execution exception."""
129
+
130
+ __slots__ = ("_diagnostic", "_messages")
131
+
132
+ def __init__(
133
+ self,
134
+ message: str = "",
135
+ *,
136
+ messages: tuple[str, ...] = (),
137
+ diagnostic: NormalizedDiagnostic | None = None,
138
+ ) -> None:
139
+ super().__init__(message)
140
+ self._messages = tuple(messages)
141
+ self._diagnostic = diagnostic
142
+
143
+ @property
144
+ def messages(self) -> tuple[str, ...]:
145
+ return self._messages
146
+
147
+ @property
148
+ def diagnostic(self) -> NormalizedDiagnostic | None:
149
+ return self._diagnostic
150
+
151
+
152
+ class TargetLost(RuntimeProbeError):
153
+ """The selected 1C debug target disappeared."""
154
+
155
+
156
+ class RdbgTransportError(ProtocolError):
157
+ """The HTTP/RDBG transport failed before a protocol outcome was proven."""
158
+
159
+
160
+ class TransportRecoveryError(RuntimeProbeError):
161
+ """A same-process RDBG reconnect could not produce sufficient evidence."""
162
+
163
+
164
+ class RecoveryIdentityMismatch(TransportRecoveryError):
165
+ """Recovered target or frame evidence differs from the checkpoint."""
166
+
167
+
168
+ class RuntimeGenerationLost(TransportRecoveryError):
169
+ """The active runtime generation can no longer be controlled safely."""
170
+
171
+
172
+ class SupervisorError(RuntimeProbeError):
173
+ """A supervised runtime generation request could not be accepted."""
174
+
175
+
176
+ class LeaseConflict(SupervisorError):
177
+ """Another frontend owns the current generation lease."""
178
+
179
+
180
+ class LeaseExpired(SupervisorError):
181
+ """The owner lease expired and the generation is terminating."""
182
+
183
+
184
+ class StaleLeaseEpoch(SupervisorError):
185
+ """The supplied lease epoch is not current."""
186
+
187
+
188
+ class StaleRuntimeGeneration(SupervisorError):
189
+ """The supplied generation is no longer active."""
190
+
191
+
192
+ class StaleProxy(ProtocolError):
193
+ """A value proxy no longer names the generation it was fenced to."""
194
+
195
+
196
+ class ReleasedProxy(ProtocolError):
197
+ """A value proxy handle was explicitly released."""
198
+
199
+
200
+ class ControllerUnavailable(SupervisorError):
201
+ """The current generation cannot accept mutating requests."""
202
+
203
+
204
+ class InvalidMessageSequence(SupervisorError):
205
+ """An IPC message was duplicated or delivered out of order."""
@@ -0,0 +1,130 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass
4
+ from hashlib import sha256
5
+ from time import monotonic
6
+
7
+ from onec_runtime.artifacts import ArtifactWriter, utc_now
8
+ from onec_runtime.errors import BslExecutionError, ProtocolError
9
+ from onec_runtime.processes import FileModeProcesses
10
+ from onec_runtime.rdbg.session import RdbgSession, SessionState
11
+
12
+
13
+ INIT_COUNTER = 'Контекст.Вставить("Счетчик", 0); Результат = Контекст.Счетчик;'
14
+ INCREMENT = 'Контекст.Счетчик = Контекст.Счетчик + 1; Результат = Контекст.Счетчик;'
15
+ RAISE_ERROR = 'ВызватьИсключение "planned-kernel-error";'
16
+
17
+
18
+ def bsl_string_literal(value: str) -> str:
19
+ normalized = value.replace("\r\n", "\n").replace("\r", "\n")
20
+ return " + Символы.ПС + ".join(
21
+ f'"{part.replace(chr(34), chr(34) * 2)}"' for part in normalized.split("\n")
22
+ )
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class CommandRecord:
27
+ command_id: int
28
+ instruction: str
29
+ instruction_hash: str
30
+ target_id: str
31
+ module_type: str
32
+ extension_name: str
33
+ object_id: str
34
+ property_id: str
35
+ line: int
36
+ start_timestamp: str
37
+ stop_timestamp: str
38
+ duration_ms: float
39
+ completed_command_id: int
40
+ result: str
41
+ error: str
42
+ observed_counter: int | None
43
+ memory: dict[str, int | None]
44
+
45
+
46
+ class KernelExperiment:
47
+ def __init__(
48
+ self,
49
+ session: RdbgSession,
50
+ processes: FileModeProcesses,
51
+ artifacts: ArtifactWriter,
52
+ *,
53
+ command_timeout_s: float = 60.0,
54
+ ) -> None:
55
+ self.session = session
56
+ self.processes = processes
57
+ self.artifacts = artifacts
58
+ self.command_timeout_s = command_timeout_s
59
+ self.command_id = 0
60
+ self.python_context: dict[str, object] = {}
61
+
62
+ @staticmethod
63
+ def _int(presentation: str) -> int:
64
+ normalized = "".join(
65
+ character
66
+ for character in presentation.strip().strip('"')
67
+ if character.isdecimal() or character in "+-"
68
+ )
69
+ return int(normalized)
70
+
71
+ def execute(self, instruction: str) -> CommandRecord:
72
+ if self.session.state is not SessionState.READY:
73
+ raise ProtocolError("Kernel command requires a READY session")
74
+ self.command_id += 1
75
+ command_id = self.command_id
76
+ start_timestamp = utc_now()
77
+ start = monotonic()
78
+ self.session.modify("ТекущаяИнструкция", bsl_string_literal(instruction))
79
+ self.session.modify("ИдентификаторКоманды", str(command_id))
80
+ self.session.continue_()
81
+ stop = self.session.wait_for_service_stop(timeout_s=self.command_timeout_s)
82
+ completed = self._int(self.session.evaluate("ЗавершеннаяКоманда").presentation)
83
+ result = self.session.evaluate("Результат").presentation
84
+ error = self.session.evaluate("Ошибка").presentation.strip('"')
85
+ counter_eval = self.session.evaluate("Контекст.Счетчик")
86
+ observed_counter = (
87
+ None if counter_eval.error_occurred else self._int(counter_eval.presentation)
88
+ )
89
+ if completed != command_id:
90
+ raise ProtocolError(
91
+ f"Completed command {completed} does not match sent command {command_id}"
92
+ )
93
+ location = stop.location
94
+ record = CommandRecord(
95
+ command_id=command_id,
96
+ instruction=instruction,
97
+ instruction_hash=sha256(instruction.encode("utf-8")).hexdigest(),
98
+ target_id=str(stop.target_id.id),
99
+ module_type=location.module_type,
100
+ extension_name=location.extension_name,
101
+ object_id=str(location.object_id),
102
+ property_id=str(location.property_id),
103
+ line=location.line,
104
+ start_timestamp=start_timestamp,
105
+ stop_timestamp=utc_now(),
106
+ duration_ms=(monotonic() - start) * 1000,
107
+ completed_command_id=completed,
108
+ result=result,
109
+ error=error,
110
+ observed_counter=observed_counter,
111
+ memory=self.processes.sample_memory(),
112
+ )
113
+ self.artifacts.append_jsonl("commands.jsonl", record)
114
+ self.artifacts.append_jsonl(
115
+ "1c-trace.jsonl",
116
+ {"timestamp": record.stop_timestamp, **asdict(record)},
117
+ )
118
+ if error:
119
+ raise BslExecutionError(error)
120
+ return record
121
+
122
+ def heartbeat(self) -> dict[str, object]:
123
+ result = {
124
+ "timestamp": utc_now(),
125
+ **self.session.heartbeat(),
126
+ "memory": self.processes.sample_memory(),
127
+ "last_command_id": self.command_id,
128
+ }
129
+ self.artifacts.append_jsonl("health.jsonl", result)
130
+ return result