litedbmodel-runtime 2.0.2__tar.gz → 2.1.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.
Files changed (24) hide show
  1. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/PKG-INFO +2 -2
  2. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/__init__.py +1 -5
  3. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/livedb_runner.py +1 -1
  4. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/runtime.py +5 -7
  5. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/static_bundle.py +96 -37
  6. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/vectors_runner.py +1 -1
  7. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime.egg-info/PKG-INFO +2 -2
  8. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime.egg-info/requires.txt +1 -1
  9. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/pyproject.toml +2 -2
  10. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_consumes_bc_core.py +14 -6
  11. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_parallel_read.py +6 -5
  12. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_runtime.py +9 -18
  13. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/README.md +0 -0
  14. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/dialect.py +0 -0
  15. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/driver.py +0 -0
  16. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/errors.py +0 -0
  17. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime/relation.py +0 -0
  18. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime.egg-info/SOURCES.txt +0 -0
  19. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime.egg-info/dependency_links.txt +0 -0
  20. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/litedbmodel_runtime.egg-info/top_level.txt +0 -0
  21. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/setup.cfg +0 -0
  22. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_conformance_corpus.py +0 -0
  23. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_dialect.py +0 -0
  24. {litedbmodel_runtime-2.0.2 → litedbmodel_runtime-2.1.0}/tests/test_render.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: litedbmodel-runtime
3
- Version: 2.0.2
3
+ Version: 2.1.0
4
4
  Summary: Thin multi-language runtime for litedbmodel v2 SCP makeSQL bundles (Python port). Executes the published static-makeSQL artifacts (a read ReadGraph = a bc surrogate ComponentGraphIR + per-node static statement templates, or a gate-first TransactionPlan) against a SQL driver — semantics-identical to the TS reference. Delegates the Expression-IR evaluation + map/Φ/wiring orchestration to behavior-contracts.
5
5
  Author: foo-ogawa
6
6
  License: MIT
7
7
  Keywords: orm,sql,ir,runtime,conformance,litedbmodel
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
- Requires-Dist: behavior-contracts==0.5.0
10
+ Requires-Dist: behavior-contracts==0.8.0
11
11
  Provides-Extra: test
12
12
  Requires-Dist: pytest>=7.0; extra == "test"
13
13
  Provides-Extra: livedb
@@ -16,8 +16,6 @@ from .dialect import SQLITE, POSTGRES, MYSQL, Dialect, dialect_for, to_dollar_pl
16
16
  from .driver import Driver, MysqlDriver, PostgresDriver, PreparedStatement, RunInfo, SqliteDriver
17
17
  from .errors import SqlFailure, map_sqlite_error
18
18
  from .static_bundle import (
19
- NODE_COMPONENT,
20
- SCOPE_PORT,
21
19
  assemble_make_sql,
22
20
  compose_make_sql,
23
21
  execute_read_graph,
@@ -38,7 +36,7 @@ from .relation import (
38
36
  run_relation_op,
39
37
  )
40
38
 
41
- __version__ = "2.0.2"
39
+ __version__ = "2.1.0"
42
40
 
43
41
  __all__ = [
44
42
  "__version__",
@@ -60,8 +58,6 @@ __all__ = [
60
58
  "SqlFailure",
61
59
  "map_sqlite_error",
62
60
  # static makeSQL bundle runtime (the sole read/render path)
63
- "NODE_COMPONENT",
64
- "SCOPE_PORT",
65
61
  "assemble_make_sql",
66
62
  "compose_make_sql",
67
63
  "execute_read_graph",
@@ -42,7 +42,7 @@ from litedbmodel_runtime import ( # noqa: E402
42
42
  read_bundle,
43
43
  )
44
44
 
45
- SUPPORTED_CORPUS_VERSION = 2
45
+ SUPPORTED_CORPUS_VERSION = 3
46
46
  # A distinct namespace per language so 4 languages share ONE docker stack without cross-talk.
47
47
  PG_SCHEMA = os.environ.get("LIVEDB_PG_SCHEMA", "scp_py")
48
48
  MYSQL_DB = os.environ.get("LIVEDB_MYSQL_DB", "scp_py")
@@ -6,10 +6,10 @@ static-makeSQL artifacts the corpus ships (pure JSON: a read ``ReadGraph`` = a b
6
6
  gate-first makeSQL statements) and executes them against a SQL driver — SEMANTICS-IDENTICAL to the
7
7
  TS reference (``src/scp/runtime.ts`` + ``src/scp/makesql/*``).
8
8
 
9
- It re-implements NO generic execution/expression evaluation: bc's ``run_behavior`` owns the
10
- plan/map/wire/output orchestration and its ``evaluate_expression`` owns the CLOSED Expression-IR
11
- (ref/refOpt/coalesce/eq/…, the SKIP guards + deferred value-specs). This module adds ONLY the
12
- SQL-backend concerns (spec §11): assemble the static makeSQL statements per dialect → bind params →
9
+ It re-implements NO generic expression evaluation: the NATIVE read-graph walker (#12) owns the
10
+ plan/map/wire/output orchestration and bc's ``evaluate_expression`` owns the CLOSED Expression-IR
11
+ (ref/refOpt/coalesce/eq/…, the SKIP guards + deferred value-specs) — NO bc ``run_behavior``. This
12
+ module adds ONLY the SQL-backend concerns (spec §11): assemble the static makeSQL statements per dialect → bind params →
13
13
  execute REAL SQL → row→result assembly; and, for a Command bundle, the gate-first write transaction
14
14
  (``execute_transaction_bundle``). This mirrors the TS runtime's division of labor exactly (bc-core
15
15
  + a makeSQL handler). The reduced fragment-tree render path (``render.py``) is RETIRED for the SQL
@@ -25,7 +25,6 @@ from .dialect import dialect_for
25
25
  from .driver import Driver
26
26
  from .errors import SqlFailure, map_sqlite_error
27
27
  from .static_bundle import (
28
- SCOPE_PORT,
29
28
  assemble_make_sql,
30
29
  execute_read_graph,
31
30
  render_placeholders,
@@ -40,7 +39,6 @@ _RETURNING_RE = re.compile(r"\breturning\b", re.IGNORECASE)
40
39
  _SELECT_RE = re.compile(r"\bselect\b", re.IGNORECASE)
41
40
 
42
41
  __all__ = [
43
- "SCOPE_PORT",
44
42
  "ENTITY_ROOT",
45
43
  "execute_bundle",
46
44
  "execute_transaction_bundle",
@@ -73,7 +71,7 @@ def _to_driver_param_tx(v: Any) -> Any:
73
71
 
74
72
 
75
73
  def execute_bundle(bundle: Mapping[str, Any], input_scope: Mapping[str, Any], driver: Driver) -> Any:
76
- """Execute a read/exec SqlBundle end-to-end (bc run_behavior + makeSQL handler).
74
+ """Execute a read/exec SqlBundle end-to-end (native read-graph walker; no bc run_behavior).
77
75
 
78
76
  The SAME code path a consumer runtime follows: it consumes ONLY the serialized bundle + bc
79
77
  runtime-core, never re-running litedbmodel's Backend-Compile. A read bundle carries a
@@ -2,10 +2,11 @@
2
2
 
3
3
  Byte-for-byte port of the TS ``src/scp/makesql/static-bundle.ts`` + ``makesql.ts`` + ``handler.ts``
4
4
  runtime halves — the SOLE makeSQL read/render path. It consumes the PRE-COMPILED, portable
5
- artifacts the corpus ships (a read ``ReadGraph`` = a bc ``ComponentGraphIR`` of ``__makeSqlNode``
6
- surrogate nodes + per-node STATIC statement templates), and EXECUTES them via the shared
7
- ``behavior-contracts`` core (``run_behavior`` drives map / Φ-merge / wiring; ``evaluate_expression``
8
- resolves the deferred value-specs + skip). This module re-implements NO generic evaluator and does
5
+ artifacts the corpus ships (a read ``ReadGraph`` = ``compileBehaviors``' REAL ``Select``/``Count``/map
6
+ ``ComponentGraphIR`` + per-node STATIC statement templates keyed by the real node id; #12 — no
7
+ ``__makeSqlNode``/``__scope`` surrogate), and EXECUTES them via the NATIVE read-graph walker (owns map /
8
+ Φ-merge / wiring; NO bc ``run_behavior``) + bc ``evaluate_expression`` for the deferred value-specs +
9
+ skip. This module re-implements NO generic evaluator and does
9
10
  NO SQL re-derivation — every statement's ``sql`` is fixed text already; the runtime only evaluates
10
11
  its deferred params + skip, resolves the WHERE connector from the present set, assembles + renders
11
12
  placeholders, and binds.
@@ -26,19 +27,15 @@ from __future__ import annotations
26
27
 
27
28
  import json
28
29
  import re
30
+ from concurrent.futures import ThreadPoolExecutor
29
31
  from typing import Any, Dict, List, Mapping, Sequence
30
32
 
31
- from behavior_contracts import evaluate_expression, run_behavior
33
+ from behavior_contracts import evaluate_expression
32
34
 
33
35
  from .dialect import Dialect, dialect_for
34
36
  from .driver import Driver
35
37
  from .errors import SqlFailure, map_sqlite_error
36
38
 
37
- # The synthetic port that carries a SQL node's render scope (mirrors TS SCOPE_PORT).
38
- SCOPE_PORT = "__scope"
39
- # The makeSQL catalog leaf name every rewritten SQL node references (mirrors TS NODE_COMPONENT).
40
- NODE_COMPONENT = "__makeSqlNode"
41
-
42
39
  _RETURNING_RE = re.compile(r"\breturning\b", re.IGNORECASE)
43
40
 
44
41
 
@@ -262,7 +259,7 @@ def render_read_primary(graph: Mapping[str, Any], input_scope: Mapping[str, Any]
262
259
  """Render the PRIMARY read node's statements of a ReadGraph → dialect SQL text + params.
263
260
 
264
261
  Byte-for-byte port of the TS ``renderReadPrimary``: the primary node is the first body node in
265
- the surrogate IR order (map nodes reference it). Optional heads are normalized to present-as-null
262
+ the real-node IR order (map nodes reference it). Optional heads are normalized to present-as-null
266
263
  first (absent-key SKIP), so an omitted optional head renders the SAME text a runtime would.
267
264
  """
268
265
  statements_by_id: Mapping[str, Any] = graph["statementsById"]
@@ -279,37 +276,99 @@ def render_read_primary(graph: Mapping[str, Any], input_scope: Mapping[str, Any]
279
276
  # ── ReadGraph execution (port of static-bundle.ts executeReadGraph) ────────────
280
277
 
281
278
 
279
+ def _plan_stages(component: Mapping[str, Any]) -> List[List[int]]:
280
+ """The plan stages (``groups``) as body-index lists, or one-node-per-stage in body order."""
281
+ plan = component.get("plan")
282
+ if isinstance(plan, Mapping):
283
+ groups = plan.get("groups")
284
+ if isinstance(groups, list):
285
+ return [[i for i in st if isinstance(i, int)] for st in groups if isinstance(st, list)]
286
+ return [[i] for i in range(len(component.get("body", [])))]
287
+
288
+
289
+ def _plan_concurrency(component: Mapping[str, Any]) -> int:
290
+ """The plan's ``concurrency`` bound (default 1 — serial when absent/<=1), for the fan-out."""
291
+ plan = component.get("plan")
292
+ if isinstance(plan, Mapping):
293
+ c = plan.get("concurrency")
294
+ if isinstance(c, int) and c >= 1:
295
+ return c
296
+ return 1
297
+
298
+
299
+ def _render_execute_node(
300
+ graph: Mapping[str, Any], node_id: str, scope: Mapping[str, Any], driver: Driver
301
+ ) -> List[Any]:
302
+ """Render node ``node_id``'s ``statementsById`` fragments against ``scope`` and run them."""
303
+ statements_by_id: Mapping[str, Any] = graph["statementsById"]
304
+ stmts = statements_by_id.get(node_id)
305
+ if stmts is None:
306
+ raise ValueError(f"static-bundle: no statements for node '{node_id}'")
307
+ rendered = render_statements(stmts, graph["dialect"], scope)
308
+ try:
309
+ return driver.prepare(rendered["sql"]).all(rendered["params"])
310
+ except Exception as e: # driver error → mapped SqlFailure
311
+ raise map_sqlite_error(e)
312
+
313
+
314
+ def _compute_read_node(
315
+ graph: Mapping[str, Any], node: Mapping[str, Any], base: Mapping[str, Any], driver: Driver
316
+ ) -> Any:
317
+ """Compute ONE read-graph body node's value: a ``cond`` join, a ``map`` (per-element
318
+ render+execute under the ``as`` binding), or a componentRef (render+execute)."""
319
+ if "cond" in node:
320
+ return evaluate_expression(node["cond"], base)
321
+ node_id = node.get("id", "")
322
+ if "map" in node:
323
+ m = node["map"]
324
+ over = evaluate_expression(m.get("over"), base)
325
+ if not isinstance(over, list):
326
+ raise ValueError(f"static-bundle: map '{node_id}': 'over' is not an array")
327
+ as_name = m.get("as") or "$"
328
+ out: List[Any] = []
329
+ for el in over:
330
+ elem_scope = dict(base)
331
+ elem_scope[as_name] = el
332
+ out.append(_render_execute_node(graph, node_id, elem_scope, driver))
333
+ return out
334
+ return _render_execute_node(graph, node_id, base, driver)
335
+
336
+
282
337
  def execute_read_graph(graph: Mapping[str, Any], input_scope: Mapping[str, Any], driver: Driver) -> Any:
283
- """Execute a compiled ReadGraph via bc ``run_behavior`` + a makeSQL handler.
338
+ """Execute a compiled ReadGraph via the NATIVE walker (#12): no bc ``run_behavior``.
284
339
 
285
- Byte-for-byte port of the TS ``executeReadGraph``: bc drives map iteration / wire binding /
286
- Φ output; the handler renders each node's static statements against the evaluated ``__scope``
287
- and runs REAL SQL. Returns the component's Φ output. This is the design's "bc composes,
288
- makeSQL executes" — the SAME path the TS runtime follows.
340
+ Walks ``compileBehaviors``' REAL ``Select``/``Count``/map node IR in ``plan.groups`` stage order —
341
+ computing each node's rows from its ``statementsById`` fragments (rendered against the walk scope)
342
+ and committing ``nodeId -> value`` — then evaluates the component ``output`` Φ expression.
343
+ litedbmodel owns map iteration / wire binding / Φ output; NO ``__makeSqlNode``/``__scope``
344
+ surrogate. The SAME native model the TS/rust/go/php runtimes follow — interpreter-free.
289
345
  """
290
- statements_by_id: Mapping[str, Any] = graph["statementsById"]
291
- dialect_name: str = graph["dialect"]
292
-
293
- def handle(ports: Mapping[str, Any], ctx: Mapping[str, Any]) -> Mapping[str, Any]:
294
- node_id = ctx["nodeId"]
295
- stmts = statements_by_id.get(node_id)
296
- if stmts is None:
297
- return {"error": f"static-bundle: no statements for node '{node_id}'"}
298
- scope = ports.get(SCOPE_PORT)
299
- if not isinstance(scope, dict):
300
- return {"error": f"static-bundle: node '{node_id}' surrogate scope did not evaluate to an object"}
301
- rendered = render_statements(stmts, dialect_name, scope)
302
- try:
303
- rows = driver.prepare(rendered["sql"]).all(rendered["params"])
304
- return {"ok": rows}
305
- except Exception as e: # driver error → mapped {error}
306
- return {"error": str(map_sqlite_error(e))}
307
-
308
- handlers = {NODE_COMPONENT: handle}
309
- ir = graph["ir"]
346
+ component = graph["ir"]["components"][0]
347
+ body = component.get("body", [])
348
+ output = component.get("output")
349
+ concurrency = _plan_concurrency(component)
310
350
  normalized = _normalize_optional_heads(list(graph.get("optionalHeads", [])), input_scope)
311
351
  try:
312
- return run_behavior(ir, handlers, normalized, graph["name"])
352
+ results: List[tuple] = []
353
+ for stage in _plan_stages(component):
354
+ base = dict(normalized)
355
+ for nid, val in results:
356
+ base[nid] = val
357
+ ordered = sorted(stage) # ascending body index — deterministic commit order
358
+ # Independent siblings of a stage run in bounded parallel (capped at the plan concurrency;
359
+ # concurrency <= 1 or a single member ⇒ serial); each dispatched on its own pooled
360
+ # connection against the driver. Results commit in ascending body index (deterministic).
361
+ if concurrency > 1 and len(ordered) > 1:
362
+ with ThreadPoolExecutor(max_workers=min(concurrency, len(ordered))) as pool:
363
+ vals = list(pool.map(lambda idx: _compute_read_node(graph, body[idx], base, driver), ordered))
364
+ else:
365
+ vals = [_compute_read_node(graph, body[idx], base, driver) for idx in ordered]
366
+ for idx, val in zip(ordered, vals):
367
+ results.append((body[idx]["id"], val))
368
+ scope = dict(normalized)
369
+ for nid, val in results:
370
+ scope[nid] = val
371
+ return evaluate_expression(output, scope)
313
372
  except Exception as e:
314
373
  raise _re_error_to_sql_failure(e)
315
374
 
@@ -47,7 +47,7 @@ from litedbmodel_runtime import ( # noqa: E402
47
47
  from litedbmodel_runtime.driver import SqliteDriver # noqa: E402
48
48
 
49
49
  # The corpus schema version this runner supports (pin — bumped on additive refreeze).
50
- SUPPORTED_CORPUS_VERSION = 2
50
+ SUPPORTED_CORPUS_VERSION = 3
51
51
 
52
52
 
53
53
  def _vectors_dir() -> Path:
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: litedbmodel-runtime
3
- Version: 2.0.2
3
+ Version: 2.1.0
4
4
  Summary: Thin multi-language runtime for litedbmodel v2 SCP makeSQL bundles (Python port). Executes the published static-makeSQL artifacts (a read ReadGraph = a bc surrogate ComponentGraphIR + per-node static statement templates, or a gate-first TransactionPlan) against a SQL driver — semantics-identical to the TS reference. Delegates the Expression-IR evaluation + map/Φ/wiring orchestration to behavior-contracts.
5
5
  Author: foo-ogawa
6
6
  License: MIT
7
7
  Keywords: orm,sql,ir,runtime,conformance,litedbmodel
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
- Requires-Dist: behavior-contracts==0.5.0
10
+ Requires-Dist: behavior-contracts==0.8.0
11
11
  Provides-Extra: test
12
12
  Requires-Dist: pytest>=7.0; extra == "test"
13
13
  Provides-Extra: livedb
@@ -1,4 +1,4 @@
1
- behavior-contracts==0.5.0
1
+ behavior-contracts==0.8.0
2
2
 
3
3
  [livedb]
4
4
  psycopg[binary]>=3.1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "litedbmodel-runtime"
7
- version = "2.0.2"
7
+ version = "2.1.0"
8
8
  description = "Thin multi-language runtime for litedbmodel v2 SCP makeSQL bundles (Python port). Executes the published static-makeSQL artifacts (a read ReadGraph = a bc surrogate ComponentGraphIR + per-node static statement templates, or a gate-first TransactionPlan) against a SQL driver — semantics-identical to the TS reference. Delegates the Expression-IR evaluation + map/Φ/wiring orchestration to behavior-contracts."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -16,7 +16,7 @@ keywords = ["orm", "sql", "ir", "runtime", "conformance", "litedbmodel"]
16
16
  # evaluation (ref/refOpt/coalesce/eq/… — the SKIP guards + param slots) to the shared common
17
17
  # core, exactly as the TS reference imports `behavior-contracts` from npm. HARD dependency,
18
18
  # consumed from the published PyPI registry (NO local path — the no-local-deps gate forbids it).
19
- dependencies = ["behavior-contracts==0.5.0"]
19
+ dependencies = ["behavior-contracts==0.8.0"]
20
20
 
21
21
  [project.optional-dependencies]
22
22
  test = ["pytest>=7.0"]
@@ -1,10 +1,11 @@
1
1
  """Guardrail test (WS7b, #31): bc runtime-core is CONSUMED, not reimplemented.
2
2
 
3
- The hard rule: the Python runtime delegates the CLOSED Expression-IR evaluation + the
4
- plan/map/wire/output orchestration to behavior-contracts (the published PyPI package), exactly
5
- like the TS reference imports `behavior-contracts` from npm. This asserts the runtime modules
6
- actually import bc's `run_behavior` / `evaluate_expression` (no local generic evaluator), and
7
- that the declared dependency is the PyPI package spec with NO local `../` path.
3
+ The hard rule: the Python runtime delegates the CLOSED Expression-IR evaluation to
4
+ behavior-contracts (the published PyPI package), exactly like the TS reference imports
5
+ `behavior-contracts` from npm — no local generic expression evaluator. (#12: the read-graph
6
+ plan/map/wire/output orchestration is now the crate's OWN NATIVE walker, not bc `run_behavior` —
7
+ mirroring the rust/go native walkers.) This asserts the runtime consumes bc's `evaluate_expression`,
8
+ does NOT call `run_behavior` on the exec path, and pins the PyPI dep with NO local `../` path.
8
9
  """
9
10
 
10
11
  from __future__ import annotations
@@ -29,7 +30,14 @@ def _imports_from(module: str) -> set[str]:
29
30
  def test_static_bundle_consumes_bc_evaluate_expression():
30
31
  names = _imports_from("static_bundle.py")
31
32
  assert "evaluate_expression" in names
32
- assert "run_behavior" in names
33
+
34
+
35
+ def test_static_bundle_does_not_call_run_behavior_on_exec_path():
36
+ # #12: the native read-graph walker replaced bc `run_behavior` on EVERY exec path — the runtime
37
+ # neither imports nor calls it (the CLOSED expression eval still rides bc `evaluate_expression`).
38
+ src = (PKG / "static_bundle.py").read_text(encoding="utf-8") + (PKG / "runtime.py").read_text(encoding="utf-8")
39
+ assert "run_behavior(" not in src, "runtime must not call bc run_behavior on the exec path (#12)"
40
+ assert "run_behavior" not in _imports_from("static_bundle.py")
33
41
 
34
42
 
35
43
  def test_no_local_generic_evaluator_reimplemented():
@@ -19,9 +19,6 @@ import time
19
19
 
20
20
  from litedbmodel_runtime.static_bundle import execute_read_graph
21
21
 
22
- SCOPE_PORT = "__scope"
23
- NODE_COMPONENT = "__makeSqlNode"
24
-
25
22
 
26
23
  class _LatencyPrepared:
27
24
  def __init__(self, driver: "_LatencyDriver", sql: str) -> None:
@@ -58,13 +55,17 @@ class _LatencyDriver:
58
55
 
59
56
 
60
57
  def _sibling_graph(n: int, concurrency: int = 16) -> dict:
61
- """A read graph of n independent sibling nodes in ONE plan stage, each a trivial SELECT."""
58
+ """A read graph of n independent sibling nodes in ONE plan stage, each a trivial SELECT.
59
+
60
+ Each body node is a REAL ``compileBehaviors`` Select node — just an ``id`` the native walker
61
+ renders + executes from ``statementsById`` (#12: no ``__makeSqlNode``/``__scope`` surrogate).
62
+ """
62
63
  body = []
63
64
  output_obj = {}
64
65
  statements_by_id = {}
65
66
  for i in range(n):
66
67
  node_id = f"rel{i}"
67
- body.append({"id": node_id, "component": NODE_COMPONENT, "ports": {SCOPE_PORT: {"obj": {}}}})
68
+ body.append({"id": node_id})
68
69
  output_obj[node_id] = {"ref": [node_id]}
69
70
  statements_by_id[node_id] = [{"sql": f"SELECT {i}", "params": []}]
70
71
  return {
@@ -2,15 +2,16 @@
2
2
 
3
3
  These exercise the static-makeSQL SQL-backend runtime against a REAL in-proc sqlite3 driver,
4
4
  independent of the frozen corpus, to prove:
5
- - read bundle → bc run_behavior (plan/map/wire/output) + a makeSQL handler → assembled Φ output;
5
+ - read bundle → the NATIVE read-graph walker (plan/map/wire/output owned by litedbmodel; #12 —
6
+ no bc run_behavior, no surrogate) → assembled Φ output;
6
7
  - write bundle → gate-first transaction (commit; requires short-circuit ROLLBACK; idempotent
7
8
  duplicate short-circuit) with `$.entity` RETURNING exposure + emit-payload JSON serialization;
8
- - bc-core is CONSUMED (the surrogate `__scope` port is evaluated by bc, the map orchestration is
9
- bc's) — not reimplemented.
9
+ - bc-core is CONSUMED only for the deferred value-specs + skip (`evaluate_expression`) — the map
10
+ orchestration is the walker's, not reimplemented per node.
10
11
 
11
- The bundle is the LOCKED static-makeSQL shape: a read carries a `readGraph` (a bc surrogate
12
- `ComponentGraphIR` of `__makeSqlNode` nodes + per-node STATIC `{sql, params, skip?, whereFragment?}`
13
- statement templates); a write carries a `transaction` plan of `{sql, params}` makeSQL ops.
12
+ The bundle is the LOCKED static-makeSQL shape: a read carries a `readGraph` (`compileBehaviors`'
13
+ REAL `Select`/map `ComponentGraphIR` + per-node STATIC `{sql, params, skip?, whereFragment?}`
14
+ statement templates keyed by node id); a write carries a `transaction` plan of `{sql, params}` ops.
14
15
  """
15
16
 
16
17
  from __future__ import annotations
@@ -63,20 +64,10 @@ def _read_bundle():
63
64
  "name": "Feed",
64
65
  "inputPorts": {"author_id": {"required": True}, "status": {"required": True}},
65
66
  "body": [
66
- {
67
- "id": "n0",
68
- "component": "__makeSqlNode",
69
- "ports": {"__scope": {"obj": {"author_id": {"ref": ["author_id"]}, "status": {"ref": ["status"]}}}},
70
- },
67
+ {"id": "n0"},
71
68
  {
72
69
  "id": "n1",
73
- "map": {
74
- "over": {"ref": ["n0"]},
75
- "as": "$e0",
76
- "component": "__makeSqlNode",
77
- "parent": "n0",
78
- "ports": {"__scope": {"obj": {"$e0": {"ref": ["$e0"]}}}},
79
- },
70
+ "map": {"over": {"ref": ["n0"]}, "as": "$e0", "parent": "n0"},
80
71
  },
81
72
  ],
82
73
  "output": {"obj": {"posts": {"ref": ["n0"]}, "authors": {"ref": ["n1"]}}},