graphddb 0.9.1 → 0.9.2

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.
package/README.md CHANGED
@@ -1,41 +1,63 @@
1
1
  # GraphDDB
2
2
 
3
- **Build GraphQL-like queries directly on DynamoDB —— while keeping every access pattern explicit.**
3
+ **Portable, contract-first DynamoDB access patterns.**
4
4
 
5
- GraphDDB is a type-safe Runtime that maps DynamoDB's native access patterns onto a GraphQL-like query
6
- model. PK / GSI / projection / relation / cursor / operation limits are all kept visible rather than hidden.
7
- It is not an ORM —— it is for **defining, validating, and executing** DynamoDB access patterns through
8
- TypeScript types.
5
+ GraphDDB lets you define your DynamoDB access patterns once in TypeScript, validate them at build time,
6
+ inspect the exact execution plan before anything runs, and execute the *same* contract from five
7
+ languages — TypeScript, Python, Rust, Go, and PHP. It is **not an ORM**: it is a contract compiler +
8
+ runtime for explicit DynamoDB access patterns.
9
9
 
10
- ## Features
10
+ The access patterns become a portable, executable artifact. TypeScript is the single source of truth;
11
+ a static planner lowers each contract to a language-neutral IR (`manifest.json` + `operations.json`),
12
+ and every language runtime executes that IR with results pinned **byte-identical** by a shared
13
+ conformance suite. GraphQL-like traversal is one of the authoring surfaces — ergonomic, but not the
14
+ point. The point is that PK / GSI / projection / relation / cursor / operation limits stay explicit,
15
+ verifiable, and portable rather than hidden behind an abstraction.
16
+
17
+ ## ✨ What GraphDDB does — in three layers
18
+
19
+ **1. Define** explicit DynamoDB access patterns
11
20
 
12
21
  - ✅ **Type-safe models** —— the TS class is the single source of truth. Keys / GSIs / field types are checked at compile time.
13
- - ✅ **Graph-style traversal** —— nest `@hasMany` / `@belongsTo` / `@hasOne` inside `select`.
14
- - ✅ **Automatic access-pattern resolution** —— the runtime picks the PK / GSI from the fields you give.
15
- - ✅ **Projection** —— only `select`ed fields are read, and only those appear in the result type.
16
- - ✅ **Execution plan (Explain)** —— inspect the execution plan before touching DynamoDB.
17
- - **CQRS contracts** —— public Query/Command contracts (N+1-safe, context boundaries).
18
- - ✅ **Python generation** —— generate a Python client + runtime from TS as the SSoT (conformance-verified).
19
- - ✅ **Testing adapter** —— unit-test planner / traversal / transaction / CDC with an in-memory executor.
20
- - ✅ **Middleware** —— host-side hooks for reads / writes (logging, tenant, authorization).
21
- - ✅ **CDC emulator** —— drive and test change events equivalent to DynamoDB Streams locally.
22
- - ✅ **CDC projection** —— `@cdcProjected()` + `fromChange` / `subscribe` parse CDC change events into typed records (sink delivery / idempotency stay with the consumer).
23
- - ✅ **Maintained access paths** —— keep embedded snapshots / aggregate counters synchronized atomically.
24
- - ✅ **CloudFormation generation** —— emit a CloudFormation template for the DynamoDB table(s) a model set maps onto (GSI union / Streams / TTL / PITR / TableClass / SSE / PROVISIONED / Auto Scaling).
25
- - ✅ **Docs generation** —— generate a model specification (Markdown + Mermaid) from the TS models; templates are Handlebars and user-overridable.
22
+ - ✅ **Graph-style traversal** —— nest `@hasMany` / `@belongsTo` / `@hasOne` inside `select` (an ergonomic authoring surface — arguments → key lookup, selection → projection).
23
+ - ✅ **CQRS contracts** —— public Query/Command contracts as the read/write authoring surface (N+1-safe, context boundaries, composition across contracts).
24
+ - ✅ **Maintained access paths** —— declare embedded snapshots / aggregate counters kept synchronized atomically with the source write.
25
+
26
+ **2. Validate & explain** before anything touches DynamoDB
27
+
28
+ - ✅ **Compile-time safety** —— undefined relations, missing GSIs, limit-less lists, and over-depth traversals are rejected at compile time / by the linter — equally for human- and AI-written code.
29
+ - ✅ **Execution plan (Explain)** —— `explain()` returns the exact DynamoDB operations, so RCU shape is inspectable up front.
30
+ - ✅ **Automatic access-pattern resolution** —— the runtime picks the PK / GSI from the fields you give; `select`ed fields are the only ones read and the only ones in the result type.
31
+ - ✅ **In-memory testing** —— unit-test planner / traversal / transaction / CDC with no Docker, no DynamoDB Local.
32
+
33
+ **3. Execute the same contract, portably, from five languages**
34
+
35
+ - ✅ **Portable executable IR** —— the static planner lowers each contract to a language-neutral bridge bundle (`manifest.json` + `operations.json`, a `components[]` graph on the shared behavior-contracts vocabulary).
36
+ - ✅ **5 language runtimes** —— generate clients + runtimes for **Python / Rust / Go / PHP** (TypeScript runs the IR natively), all executing the same access patterns.
37
+ - ✅ **5-language conformance** —— TS / Python / Rust / Go / PHP run the same cases against DynamoDB Local; CI pins the results **byte-identical**.
38
+
39
+ **Operational surface** (all built on the layers above): **Middleware** (host-side read/write hooks) ·
40
+ **CDC emulator** (local DynamoDB-Streams-equivalent change events) · **CDC projection**
41
+ (`@cdcProjected()` + `fromChange` / `subscribe` into typed records) · **Prepared statements**
42
+ (compile-once / execute-many, AOT static plans) · **CloudFormation generation** ·
43
+ **Docs generation** (Markdown + Mermaid, Handlebars-overridable).
26
44
 
27
45
  ## 🤔 Philosophy
28
46
 
47
+ - **Access patterns as portable contracts** —— an access pattern is defined once and becomes a
48
+ language-neutral, executable artifact. The same contract is validated, explained, and then executed
49
+ identically across languages, instead of being re-implemented per stack.
29
50
  - **Native DynamoDB access patterns** —— express access patterns directly in code instead of hiding them
30
51
  behind an ORM abstraction. Because PK / GSI, projection, and limits stay visible, the correct design
31
52
  becomes the easiest path.
32
- - **Graph-style traversal** —— GraphQL's query model (arguments → key lookup, selection → projection,
33
- relation → Query/Get/BatchGet) corresponds naturally to DynamoDB's access patterns.
34
53
  - **Compile-time safety** —— undefined relations, missing GSIs, limit-less lists, and traversals exceeding
35
54
  the allowed depth are rejected before execution at compile time / by the linter. The same constraints
36
55
  apply equally to human-written and AI-generated code.
37
56
  - **Runtime transparency** —— the runtime is not a black box. `explain()` shows the execution plan, and the
38
57
  plan reveals the shape of RCU usage.
58
+ - **Graph-style traversal is a surface, not the essence** —— GraphQL's query model (arguments → key
59
+ lookup, selection → projection, relation → Query/Get/BatchGet) is a convenient way to *author* access
60
+ patterns; the essence is the explicit, portable contract underneath.
39
61
 
40
62
  ## 📦 Install
41
63
 
@@ -57,7 +79,7 @@ Node.js ≥ 22 is required.
57
79
  ## 🚀 Quick Start
58
80
 
59
81
  ```ts
60
- import { DDBModel, model, string, key, k } from 'graphddb';
82
+ import { DDBModel, graphddb, model, string, key, k } from 'graphddb';
61
83
  import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
62
84
 
63
85
  @model({ table: 'AppTable', prefix: 'USER' })
@@ -200,8 +222,16 @@ Each capability is summarized here only. For details, operator lists, and proced
200
222
  authorization scoping). Host-only and non-serialized. For hook points, see [`docs/middleware.md`](./docs/middleware.md).
201
223
  - **Class hydration** —— `options.hydrate` loads read results into host-language domain objects (opt-in,
202
224
  Phase 1: `query` top level). [`docs/class-hydration.md`](./docs/class-hydration.md).
203
- - **Python bridge** —— generate a Python client + runtime with TS as the SSoT, kept in step by a TS↔Python
204
- conformance suite. [`docs/python-bridge.md`](./docs/python-bridge.md).
225
+ - **Multi-language bridge** —— generate Python / Rust / Go / PHP clients + runtimes with TS as the SSoT,
226
+ kept in step by a 5-language conformance suite. [`docs/python-bridge.md`](./docs/python-bridge.md).
227
+ - **Prepared statements** —— `graphddb.prepare($ => ({...}))` → `.execute(params)` (unified read/write).
228
+ "Contract-free precompilation": compile a declarative route once and execute it repeatedly with
229
+ different params. With the **true build-time compilation (AOT)** of `graphddb transform prepared
230
+ --aot`, plans are emitted as static artifacts and zero runtime compilation happens, including the
231
+ first call (a stale plan is loud-rejected at load; drift is caught in CI). Without the transform,
232
+ behavior stays identical through the lazy-slot + structural-memoization fallback. no-runtime-capture
233
+ is loudly enforced by a build-time lint + a runtime guard.
234
+ [`docs/prepared-statements.md`](./docs/prepared-statements.md).
205
235
  - **CQRS contracts** —— public Query/Command contracts (cardinality matrix, N+1 safety, context boundaries,
206
236
  composition across contracts). [`docs/cqrs-contract.md`](./docs/cqrs-contract.md) /
207
237
  [`docs/mutation-command-derivation.md`](./docs/mutation-command-derivation.md).
@@ -212,6 +242,17 @@ Each capability is summarized here only. For details, operator lists, and proced
212
242
  `graphddb.subscribe(handlers)` (the sibling of `query` / `mutate`) produces a `ChangeHandler` the
213
243
  consumer mounts on its own stream. graphddb owns parse→typed record only; subscription, sink
214
244
  delivery, and idempotency are the consumer's. [`docs/cdc-projection.md`](./docs/cdc-projection.md).
245
+ - **Multi-language codegen (the 3 paths, #257)** —— execution keeps 2 paths + 1 consumer surface,
246
+ coexisting permanently: (1) **dynamic JSON path (default)** — the `components[]` of
247
+ `operations.json` are loaded at runtime and interpreted by the shared `run_behavior` (for swapping
248
+ behavior without a deploy). (2) **codegen-static path (opt-in)** — `graphddb generate behaviors
249
+ --lang <ts|python|go|rust|php>` hands the same IR to the **shared upstream behavior-contracts
250
+ generator** (bc#13), emitting modules with the IR baked in as native literals (graphddb owns only
251
+ envelope + invoke — no generation logic). A generated module checks its fingerprint against the
252
+ live registry and loud-rejects when stale (#208 discipline). Rust generated modules use
253
+ `std::sync::LazyLock`, so **Rust >= 1.80** is required. (3) **typed bindings
254
+ (`generate python/php/rust/go`)** — the consumer-UX surface (typed repositories / DTOs), still
255
+ graphddb-owned; not an execution engine — it delegates to the paths above.
215
256
  - **CloudFormation generation** —— `graphddb generate cloudformation` emits a CloudFormation template for
216
257
  the DynamoDB table(s) a model set maps onto (GSI union / Streams / TTL / PITR / PROVISIONED / Auto
217
258
  Scaling). [`docs/cloudformation.md`](./docs/cloudformation.md).
@@ -232,10 +273,11 @@ documentation available offline at hand. On GitHub, follow the links in the tabl
232
273
  | [Specification](./docs/spec.md) | Core API: entities, structured keys/GSIs, query/filter, relations, batch/transaction, design rules, runtime behavior. |
233
274
  | [Design patterns](./docs/design-patterns.md) | Mapping representative DynamoDB design patterns onto graphddb features (how to declare `pattern` / `@model({ kind })` + `@maintainedFrom` / `@aggregate`, read & write maintenance, per-phase coverage). |
234
275
  | [Middleware / Hooks](./docs/middleware.md) | The `graphddb.config.use` host-side middleware: hook points read R1–R5 / write W1–W5, `{ context }`, ordering. |
276
+ | [Prepared statements](./docs/prepared-statements.md) | `graphddb.prepare` / `.execute` (unified read/write prepared statements), the no-runtime-capture constraint, `graphddb transform prepared` (AOT static plans / compile-time hoisting + build-time lint + drift detection): choosing between the 3 tiers AOT > lazy slot + structural memoization > ad-hoc. |
235
277
  | [CQRS contract layer](./docs/cqrs-contract.md) | Public Query/Command contracts, cardinality matrix, N+1 safety, composition across contracts, context boundaries. |
236
278
  | [Mutation → command derivation](./docs/mutation-command-derivation.md) | The internal write-plan composition DSL behind the Command IF (`entityWrites`, fragment composition, derivation of atomic `TransactWriteItems`). |
237
279
  | [Class hydration](./docs/class-hydration.md) | Opt-in `options.hydrate` that loads read results into host objects (Phase 1: `query` top level). |
238
- | [Multi-language / Python bridge](./docs/python-bridge.md) | Code generation with TS as the SSoT and a Python runtime; TS↔Python conformance. |
280
+ | [Multi-language bridge](./docs/python-bridge.md) | Code generation with TS as the SSoT and Python / Rust / Go / PHP runtimes; 5-language conformance. |
239
281
  | [In-memory test adapter](./docs/testing.md) | Docker-free in-process testing with `graphddb/testing` and `MemoryInspector`. |
240
282
  | [CDC emulator](./docs/cdc-emulator.md) | A change-event emulator for differential aggregation patterns (dev/test). |
241
283
  | [CDC projection](./docs/cdc-projection.md) | The `@cdcProjected()` + `fromChange` / `subscribe` typed-consumer-IF: a contract that parses CDC change events into typed records. Boundary (parse→typed is graphddb; subscription, sink delivery, idempotency are the consumer's). |
@@ -256,23 +298,30 @@ documentation available offline at hand. On GitHub, follow the links in the tabl
256
298
 
257
299
  A query travels from the TS Model through the Planner / Runtime to DynamoDB:
258
300
 
259
- ```mermaid
260
- flowchart LR
261
- M["TS Model<br/>Entity / Key / GSI / Relation"] --> P["Planner<br/>access pattern resolution / projection"]
262
- P --> R["Runtime<br/>execute / retry / hydrate"]
263
- R --> D[("DynamoDB")]
264
- ```
301
+ ![Query execution pipeline: TS Model → Planner → Runtime → DynamoDB](./docs/diagrams/query-pipeline.en.svg)
265
302
 
266
- From the same TS Model (the SSoT), multiple targets are derived:
303
+ From the same TS Model (the SSoT), multiple targets are derived. The language runtimes are fanned out to
304
+ 4 languages through the portable IR (the `components[]` graph in `manifest.json` + `operations.json`),
305
+ and the execution results of all 5 languages — TS included — are pinned byte-identical by the
306
+ conformance suite:
267
307
 
268
- ```mermaid
269
- flowchart LR
270
- M["TS Model (SSoT)"] --> RT["Runtime (TS)"]
271
- M --> PY["Python client + runtime"]
272
- M --> CQ["CQRS Contract"]
273
- M --> CFN["CloudFormation template"]
274
- M --> DOC["Model docs (Markdown + Mermaid)"]
275
- ```
308
+ ![SSoT derivation: TS Model → TS runtime / portable IR → 4 language runtimes / CQRS / CloudFormation / docs](./docs/diagrams/ssot-derivation.en.svg)
309
+
310
+ | Runtime | Package | Distribution |
311
+ |---------|---------|--------------|
312
+ | TypeScript | `graphddb` | npm |
313
+ | Python | `graphddb-runtime` | PyPI |
314
+ | Rust | `graphddb_runtime` | crates.io |
315
+ | Go | `github.com/foo-log-inc/graphddb/go` | go module (`go/vX.Y.Z` tags) |
316
+ | PHP | `graphddb/runtime` | bundled in-repo (not on composer) |
317
+
318
+ Multi-language execution keeps 3 permanent paths — 2 execution paths + 1 consumer surface (see
319
+ "Multi-language codegen" under [More Capabilities](#-more-capabilities)):
320
+
321
+ ![The three multi-language execution paths: authoring → static planner → portable IR → dynamic JSON / codegen-static / typed bindings](./docs/diagrams/execution-paths.en.svg)
322
+
323
+ > The figures are self-contained SVGs drawn with diagram-contracts (Draw TSX).
324
+ > Sources live in [`diagrams/`](./diagrams/); regenerate with `diagrams/build.sh`.
276
325
 
277
326
  ## 📄 License
278
327
 
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 988 555.6" width="988" height="555.6" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ <marker id="marker-filledArrow-6b46c1" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#6b46c1"/></marker>
5
+ </defs>
6
+ <rect x="0" y="0" width="988" height="555.6" fill="#ffffff"/>
7
+ <g id="vstack_1"><g id="hstack_1"><g id="box_1"><rect x="18" y="62.099999999999994" width="160" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="def"><rect x="178" y="18" width="264" height="89.19999999999999" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_2"><g id="text_1"><text x="310" y="46.75" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="310" dy="0">Contract / behavior authoring</tspan></text></g><g id="text_2"><text x="310" y="69.075" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="310" dy="0">publishQuery / publishCommand /</tspan></text></g><g id="text_3"><text x="310" y="90.175" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="310" dy="0">publishBehaviors</tspan></text></g></g></g><g id="box_2"><rect x="442" y="62.099999999999994" width="120" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="plan"><rect x="562" y="18" width="248" height="89.19999999999999" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_3"><g id="text_4"><text x="686" y="46.75" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="686" dy="0">Static planner</tspan></text></g><g id="text_5"><text x="685.9999999999999" y="69.075" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="685.9999999999999" dy="0">symbolic key evaluation /</tspan></text></g><g id="text_6"><text x="686" y="90.175" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="686" dy="0">bridge guard (rejects non-declarative)</tspan></text></g></g></g></g><g id="hstack_2"><g id="box_3"><rect x="18" y="195.29999999999998" width="340" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="ir"><rect x="358" y="151.2" width="272" height="89.19999999999999" rx="10" fill="#eef3fc" stroke="#2b4bab" stroke-width="1.5"/><g id="vstack_4"><g id="text_7"><text x="494" y="179.95" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="494" dy="0">Portable IR (bridge bundle)</tspan></text></g><g id="text_8"><text x="494" y="202.27499999999998" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="494" dy="0">manifest.json + operations.json</tspan></text></g><g id="text_9"><text x="494" y="223.37499999999997" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="494" dy="0">components[] graph</tspan></text></g></g></g></g><g id="hstack_3"><g id="p1"><rect x="18" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#2f855a" stroke-width="1.5"/><g id="vstack_5"><g id="hstack_4"><g id="box_4"><rect x="30" y="329.87" width="108.79999999999997" height="22.7" rx="11.35" fill="#2f855a" stroke="#e5e7eb" stroke-width="0"/><g id="text_10"><text x="84.39999999999998" y="344.895" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="84.39999999999998" dy="0">Path 1 — default</tspan></text></g></g><g id="text_11"><text x="146.79999999999995" y="345.77" text-anchor="start" fill="#22543d" font-size="13" font-weight="bold"><tspan x="146.79999999999995" dy="0">Dynamic JSON</tspan></text></g></g><g id="text_12"><text x="30" y="374.90999999999997" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">Loads components[] at runtime;</tspan></text></g><g id="text_13"><text x="30" y="401.03" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">the shared run_behavior interprets it.</tspan></text></g><g id="text_14"><text x="30" y="427.15" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">Swap behavior without a deploy.</tspan></text></g></g></g><g id="box_5"><rect x="312" y="296.4" width="35" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="p2"><rect x="347" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#2b6cb0" stroke-width="1.5"/><g id="vstack_6"><g id="hstack_5"><g id="box_6"><rect x="359" y="316.80999999999995" width="102.49999999999997" height="22.7" rx="11.35" fill="#2b6cb0" stroke="#e5e7eb" stroke-width="0"/><g id="text_15"><text x="410.25" y="331.8349999999999" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="410.25" dy="0">Path 2 — opt-in</tspan></text></g></g><g id="text_16"><text x="469.5" y="332.7099999999999" text-anchor="start" fill="#1d3a8f" font-size="13" font-weight="bold"><tspan x="469.5" dy="0">codegen-static</tspan></text></g></g><g id="text_17"><text x="359" y="361.8499999999999" text-anchor="start" fill="#1d3a8f" font-size="10.8" font-weight="medium"><tspan x="359" dy="0">generate behaviors</tspan></text></g><g id="text_18"><text x="359" y="387.9699999999999" text-anchor="start" fill="#1d3a8f" font-size="10.8" font-weight="medium"><tspan x="359" dy="0">--lang &lt;ts|python|go|rust|php&gt;</tspan></text></g><g id="text_19"><text x="359" y="414.0899999999999" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="359" dy="0">Bakes the IR in as native literals.</tspan></text></g><g id="text_20"><text x="359" y="440.2099999999999" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="359" dy="0">Fingerprint check loud-rejects stale.</tspan></text></g></g></g><g id="box_7"><rect x="641" y="296.4" width="35" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="p3"><rect x="676" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#6b46c1" stroke-width="1.5"/><g id="vstack_7"><g id="hstack_6"><g id="box_8"><rect x="688" y="329.87" width="77.29999999999998" height="22.7" rx="11.35" fill="#6b46c1" stroke="#e5e7eb" stroke-width="0"/><g id="text_21"><text x="726.65" y="344.895" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="726.65" dy="0">consumer UX</tspan></text></g></g><g id="text_22"><text x="773.3" y="345.77" text-anchor="start" fill="#44337a" font-size="13" font-weight="bold"><tspan x="773.3" dy="0">Typed bindings</tspan></text></g></g><g id="text_23"><text x="688" y="374.90999999999997" text-anchor="start" fill="#44337a" font-size="10.8" font-weight="medium"><tspan x="688" dy="0">generate python|php|rust|go</tspan></text></g><g id="text_24"><text x="688" y="401.03" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="688" dy="0">Generates typed repositories / DTOs.</tspan></text></g><g id="text_25"><text x="688" y="427.15" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="688" dy="0">Not an engine — delegates to path 1 / 2.</tspan></text></g></g></g></g><g id="note"><rect x="18" y="486.4" width="952" height="51.199999999999996" rx="8" fill="#fbfcfe" stroke="#5886cd" stroke-width="1.2" stroke-dasharray="6 4"/><g id="vstack_8"><g id="text_26"><text x="32" y="506.47499999999997" text-anchor="start" fill="#33415c" font-size="11.5"><tspan x="32" dy="0">The 2 execution paths + 1 consumer surface coexist permanently (#257).</tspan></text></g><g id="text_27"><text x="32" y="525.575" text-anchor="start" fill="#33415c" font-size="11.5"><tspan x="32" dy="0">All 5 languages (TS / Python / Rust / Go / PHP) execute the same IR, and conformance pins the results byte-identical.</tspan></text></g></g></g></g>
8
+ <g id="connector_1"><path d="M 442 62.599999999999994 C 481.6 62.599999999999994, 522.4 62.599999999999994, 562 62.599999999999994" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_2"><path d="M 686 107.19999999999999 C 686 154.873020294502, 548.4 103.52697970549798, 548.4 151.2" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ <g id="connector_3"><path d="M 398.8 240.39999999999998 C 398.8 319.7363101990507, 165 217.06368980094925, 165 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
11
+ <g id="connector_4"><path d="M 494 240.39999999999998 C 494 258.88, 494 277.91999999999996, 494 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
12
+ <g id="connector_5"><path d="M 589.2 240.39999999999998 C 589.2 319.7363101990507, 823 217.06368980094925, 823 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
13
+ <g id="connector_6"><path d="M 676 380.4 C 664.45 380.4, 652.55 380.4, 641 380.4" fill="none" stroke="#6b46c1" stroke-width="1.6" stroke-dasharray="6 4" marker-end="url(#marker-filledArrow-6b46c1)"/></g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 988 536.5" width="988" height="536.5" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ <marker id="marker-filledArrow-6b46c1" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#6b46c1"/></marker>
5
+ </defs>
6
+ <rect x="0" y="0" width="988" height="536.5" fill="#ffffff"/>
7
+ <g id="vstack_1"><g id="hstack_1"><g id="box_1"><rect x="18" y="62.099999999999994" width="160" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="def"><rect x="178" y="18" width="264" height="89.19999999999999" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_2"><g id="text_1"><text x="310" y="46.75" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="310" dy="0">コントラクト / ビヘイビア定義</tspan></text></g><g id="text_2"><text x="310" y="69.075" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="310" dy="0">publishQuery / publishCommand /</tspan></text></g><g id="text_3"><text x="310" y="90.175" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="310" dy="0">publishBehaviors</tspan></text></g></g></g><g id="box_2"><rect x="442" y="62.099999999999994" width="120" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="plan"><rect x="562" y="18" width="248" height="89.19999999999999" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_3"><g id="text_4"><text x="686" y="46.75" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="686" dy="0">Static planner</tspan></text></g><g id="text_5"><text x="686" y="69.075" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="686" dy="0">symbolic key evaluation /</tspan></text></g><g id="text_6"><text x="686" y="90.175" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="686" dy="0">bridge guard(非宣言的な定義を拒否)</tspan></text></g></g></g></g><g id="hstack_2"><g id="box_3"><rect x="18" y="195.29999999999998" width="340" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="ir"><rect x="358" y="151.2" width="272" height="89.19999999999999" rx="10" fill="#eef3fc" stroke="#2b4bab" stroke-width="1.5"/><g id="vstack_4"><g id="text_7"><text x="494" y="179.95" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="494" dy="0">Portable IR(bridge bundle)</tspan></text></g><g id="text_8"><text x="494" y="202.27499999999998" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="494" dy="0">manifest.json + operations.json</tspan></text></g><g id="text_9"><text x="494" y="223.37499999999997" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="494" dy="0">components[] グラフ</tspan></text></g></g></g></g><g id="hstack_3"><g id="p1"><rect x="18" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#2f855a" stroke-width="1.5"/><g id="vstack_5"><g id="hstack_4"><g id="box_4"><rect x="30" y="329.87" width="81.5" height="22.7" rx="11.35" fill="#2f855a" stroke="#e5e7eb" stroke-width="0"/><g id="text_10"><text x="70.75" y="344.895" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="70.75" dy="0">経路 1 — 既定</tspan></text></g></g><g id="text_11"><text x="119.5" y="345.77" text-anchor="start" fill="#22543d" font-size="13" font-weight="bold"><tspan x="119.5" dy="0">JSON 動的</tspan></text></g></g><g id="text_12"><text x="30" y="374.90999999999997" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">components[] を実行時にロードし、</tspan></text></g><g id="text_13"><text x="30" y="401.03" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">共有 run_behavior が解釈実行する。</tspan></text></g><g id="text_14"><text x="30" y="427.15" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="30" dy="0">デプロイなしの振る舞い差し替え向け。</tspan></text></g></g></g><g id="box_5"><rect x="312" y="296.4" width="35" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="p2"><rect x="347" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#2b6cb0" stroke-width="1.5"/><g id="vstack_6"><g id="hstack_5"><g id="box_6"><rect x="359" y="316.80999999999995" width="98.29999999999998" height="22.7" rx="11.35" fill="#2b6cb0" stroke="#e5e7eb" stroke-width="0"/><g id="text_15"><text x="408.15" y="331.8349999999999" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="408.15" dy="0">経路 2 — opt-in</tspan></text></g></g><g id="text_16"><text x="465.29999999999995" y="332.7099999999999" text-anchor="start" fill="#1d3a8f" font-size="13" font-weight="bold"><tspan x="465.29999999999995" dy="0">codegen-static</tspan></text></g></g><g id="text_17"><text x="359" y="361.8499999999999" text-anchor="start" fill="#1d3a8f" font-size="10.8" font-weight="medium"><tspan x="359" dy="0">generate behaviors</tspan></text></g><g id="text_18"><text x="359" y="387.9699999999999" text-anchor="start" fill="#1d3a8f" font-size="10.8" font-weight="medium"><tspan x="359" dy="0">--lang &lt;ts|python|go|rust|php&gt;</tspan></text></g><g id="text_19"><text x="359" y="414.0899999999999" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="359" dy="0">IR をネイティブリテラルとして焼き込み。</tspan></text></g><g id="text_20"><text x="359" y="440.2099999999999" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="359" dy="0">fingerprint 照合で stale を loud reject。</tspan></text></g></g></g><g id="box_7"><rect x="641" y="296.4" width="35" height="1" fill="#ffffff" stroke="#e5e7eb" stroke-width="0" opacity="0"/></g><g id="p3"><rect x="676" y="296.4" width="294" height="168" rx="10" fill="white" stroke="#6b46c1" stroke-width="1.5"/><g id="vstack_7"><g id="hstack_6"><g id="box_8"><rect x="688" y="329.87" width="39.5" height="22.7" rx="11.35" fill="#6b46c1" stroke="#e5e7eb" stroke-width="0"/><g id="text_21"><text x="707.75" y="344.895" text-anchor="middle" fill="white" font-size="10.5" font-weight="bold"><tspan x="707.75" dy="0">消費面</tspan></text></g></g><g id="text_22"><text x="735.5" y="345.77" text-anchor="start" fill="#44337a" font-size="13" font-weight="bold"><tspan x="735.5" dy="0">型付き bindings</tspan></text></g></g><g id="text_23"><text x="688" y="374.90999999999997" text-anchor="start" fill="#44337a" font-size="10.8" font-weight="medium"><tspan x="688" dy="0">generate python|php|rust|go</tspan></text></g><g id="text_24"><text x="688" y="401.03" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="688" dy="0">typed repositories / DTO を生成。</tspan></text></g><g id="text_25"><text x="688" y="427.15" text-anchor="start" fill="#444444" font-size="10.8"><tspan x="688" dy="0">実行エンジンではなく経路 1 / 2 へ委譲。</tspan></text></g></g></g></g><g id="note"><rect x="18" y="486.4" width="952" height="32.099999999999994" rx="8" fill="#fbfcfe" stroke="#5886cd" stroke-width="1.2" stroke-dasharray="6 4"/><g id="vstack_8"><g id="text_26"><text x="32" y="506.47499999999997" text-anchor="start" fill="#33415c" font-size="11.5"><tspan x="32" dy="0">実行 2 経路 + 消費面 1 面は恒久併存(#257)。5言語(TS / Python / Rust / Go / PHP)が同一の IR を実行し、conformance が byte-identical を固定する。</tspan></text></g></g></g></g>
8
+ <g id="connector_1"><path d="M 442 62.599999999999994 C 481.6 62.599999999999994, 522.4 62.599999999999994, 562 62.599999999999994" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_2"><path d="M 686 107.19999999999999 C 686 154.873020294502, 548.4 103.52697970549798, 548.4 151.2" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ <g id="connector_3"><path d="M 398.8 240.39999999999998 C 398.8 319.7363101990507, 165 217.06368980094925, 165 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
11
+ <g id="connector_4"><path d="M 494 240.39999999999998 C 494 258.88, 494 277.91999999999996, 494 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
12
+ <g id="connector_5"><path d="M 589.2 240.39999999999998 C 589.2 319.7363101990507, 823 217.06368980094925, 823 296.4" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
13
+ <g id="connector_6"><path d="M 676 380.4 C 664.45 380.4, 652.55 380.4, 641 380.4" fill="none" stroke="#6b46c1" stroke-width="1.6" stroke-dasharray="6 4" marker-end="url(#marker-filledArrow-6b46c1)"/></g>
14
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 950 122.9" width="950" height="122.9" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ </defs>
5
+ <rect x="0" y="0" width="950" height="122.9" fill="#ffffff"/>
6
+ <g id="hstack_1"><g id="m"><rect x="18" y="27.400000000000006" width="196" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_1"><g id="text_1"><text x="116" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="116" dy="0">TS Model</tspan></text></g><g id="text_2"><text x="116" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="116" dy="0">Entity / Key / GSI / Relation</tspan></text></g></g></g><g id="p"><rect x="268" y="27.400000000000006" width="236" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_2"><g id="text_3"><text x="386" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="386" dy="0">Planner</tspan></text></g><g id="text_4"><text x="386" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="386" dy="0">access-pattern resolution / projection</tspan></text></g></g></g><g id="r"><rect x="558" y="27.400000000000006" width="196" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_3"><g id="text_5"><text x="656" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="656" dy="0">Runtime</tspan></text></g><g id="text_6"><text x="656" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="656" dy="0">execute / retry / hydrate</tspan></text></g></g></g><g id="d"><path d="M 808,26.69 A 62,8.690000000000001 0 0,1 932,26.69 L 932,96.21000000000001 A 62,8.690000000000001 0 0,1 808,96.21000000000001 L 808,26.69" fill="#eef3fc" stroke="#4a6bd8" stroke-width="1.5"/><path d="M 808,26.69 A 62,8.690000000000001 0 0,0 932,26.69" fill="none" stroke="#4a6bd8" stroke-width="1.5"/><g id="text_7"><text x="870" y="66.175" text-anchor="middle" fill="#2b4bab" font-size="13.5" font-weight="bold"><tspan x="870" dy="0">DynamoDB</tspan></text></g></g></g>
7
+ <g id="connector_1"><path d="M 214 61.45 C 231.82 61.45, 250.18 61.45, 268 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
8
+ <g id="connector_2"><path d="M 504 61.45 C 521.82 61.45, 540.18 61.45, 558 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_3"><path d="M 754 61.45 C 771.82 61.45, 790.18 61.45, 808 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 930 122.9" width="930" height="122.9" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ </defs>
5
+ <rect x="0" y="0" width="930" height="122.9" fill="#ffffff"/>
6
+ <g id="hstack_1"><g id="m"><rect x="18" y="27.400000000000006" width="196" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_1"><g id="text_1"><text x="116" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="116" dy="0">TS Model</tspan></text></g><g id="text_2"><text x="116" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="116" dy="0">Entity / Key / GSI / Relation</tspan></text></g></g></g><g id="p"><rect x="268" y="27.400000000000006" width="216" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_2"><g id="text_3"><text x="376" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="376" dy="0">Planner</tspan></text></g><g id="text_4"><text x="376" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="376" dy="0">access pattern 解決 / projection</tspan></text></g></g></g><g id="r"><rect x="538" y="27.400000000000006" width="196" height="68.1" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_3"><g id="text_5"><text x="636" y="56.150000000000006" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="636" dy="0">Runtime</tspan></text></g><g id="text_6"><text x="636" y="78.47500000000001" text-anchor="middle" fill="#555555" font-size="11.5"><tspan x="636" dy="0">execute / retry / hydrate</tspan></text></g></g></g><g id="d"><path d="M 788,26.69 A 62,8.690000000000001 0 0,1 912,26.69 L 912,96.21000000000001 A 62,8.690000000000001 0 0,1 788,96.21000000000001 L 788,26.69" fill="#eef3fc" stroke="#4a6bd8" stroke-width="1.5"/><path d="M 788,26.69 A 62,8.690000000000001 0 0,0 912,26.69" fill="none" stroke="#4a6bd8" stroke-width="1.5"/><g id="text_7"><text x="850" y="66.175" text-anchor="middle" fill="#2b4bab" font-size="13.5" font-weight="bold"><tspan x="850" dy="0">DynamoDB</tspan></text></g></g></g>
7
+ <g id="connector_1"><path d="M 214 61.45 C 231.82 61.45, 250.18 61.45, 268 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
8
+ <g id="connector_2"><path d="M 484 61.45 C 501.82 61.45, 520.18 61.45, 538 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_3"><path d="M 734 61.45 C 751.82 61.45, 770.18 61.45, 788 61.45" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 988.3999999999979 582.9" width="988.3999999999979" height="582.9" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ </defs>
5
+ <rect x="0" y="0" width="988.3999999999979" height="582.9" fill="#ffffff"/>
6
+ <g id="vstack_1"><g id="hstack_1"><g id="ssot"><rect x="18" y="231.35000000000002" width="180" height="68.1" rx="10" fill="#eef3fc" stroke="#2b4bab" stroke-width="1.5"/><g id="vstack_2"><g id="text_1"><text x="108" y="260.1" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="108" dy="0">TS Model</tspan></text></g><g id="text_2"><text x="108" y="282.425" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="108" dy="0">(SSoT — single source of truth)</tspan></text></g></g></g><g id="vstack_3"><g id="rt"><rect x="288" y="18" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_4"><g id="text_3"><text x="302" y="42.175" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Runtime (TS)</tspan></text></g><g id="text_4"><text x="302" y="61.449999999999996" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">live execution — query / list / mutate / subscribe / explain</tspan></text></g></g></g><g id="ir"><rect x="288" y="91.3" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_5"><g id="text_5"><text x="302" y="115.475" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Portable IR (bridge bundle)</tspan></text></g><g id="text_6"><text x="302" y="134.75" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">manifest.json + operations.json — components[] graph (shared behavior-contracts vocabulary)</tspan></text></g></g></g><g id="langs"><rect x="288" y="196.6" width="620" height="96.3" rx="10" fill="#f7f9fd" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_6"><g id="box_1"><rect x="288" y="196.6" width="620" height="28.799999999999997" rx="9" fill="#1d3a8f" stroke="#e5e7eb" stroke-width="0"/><g id="text_7"><text x="598" y="215.2" text-anchor="middle" fill="white" font-size="12" font-weight="bold"><tspan x="598" dy="0">Generated clients + runtimes (4 languages)</tspan></text></g></g><g id="box_2"><rect x="288" y="225.39999999999998" width="620" height="67.5" fill="none" stroke="#e5e7eb" stroke-width="0"/><g id="hstack_2"><g id="py"><rect x="298" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#3776ab" stroke-width="1.8"/><g id="vstack_7"><g id="text_8"><text x="368" y="256.04999999999995" text-anchor="middle" fill="#3776ab" font-size="13" font-weight="bold"><tspan x="368" dy="0">Python</tspan></text></g><g id="text_9"><text x="368" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="368" dy="0">graphddb-runtime (PyPI)</tspan></text></g></g></g><g id="rs"><rect x="448" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#b7410e" stroke-width="1.8"/><g id="vstack_8"><g id="text_10"><text x="518" y="256.04999999999995" text-anchor="middle" fill="#b7410e" font-size="13" font-weight="bold"><tspan x="518" dy="0">Rust</tspan></text></g><g id="text_11"><text x="518" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="518" dy="0">graphddb_runtime (crates.io)</tspan></text></g></g></g><g id="go"><rect x="598" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#007d9c" stroke-width="1.8"/><g id="vstack_9"><g id="text_12"><text x="668" y="256.04999999999995" text-anchor="middle" fill="#007d9c" font-size="13" font-weight="bold"><tspan x="668" dy="0">Go</tspan></text></g><g id="text_13"><text x="668" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="668" dy="0">go module (go/vX.Y.Z tag)</tspan></text></g></g></g><g id="php"><rect x="748" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#777bb4" stroke-width="1.8"/><g id="vstack_10"><g id="text_14"><text x="818" y="256.04999999999995" text-anchor="middle" fill="#777bb4" font-size="13" font-weight="bold"><tspan x="818" dy="0">PHP</tspan></text></g><g id="text_15"><text x="818" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="818" dy="0">graphddb/runtime (in-repo)</tspan></text></g></g></g></g></g></g></g><g id="cq"><rect x="288" y="308.9" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_11"><g id="text_16"><text x="302" y="333.075" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">CQRS Contract</tspan></text></g><g id="text_17"><text x="302" y="352.34999999999997" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">public Query / Command contracts (N+1-safe, context boundaries)</tspan></text></g></g></g><g id="cfn"><rect x="288" y="382.2" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_12"><g id="text_18"><text x="302" y="406.375" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">CloudFormation template</tspan></text></g><g id="text_19"><text x="302" y="425.65" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">generate cloudformation — GSI union / Streams / TTL / PITR / Auto Scaling</tspan></text></g></g></g><g id="doc"><rect x="288" y="455.5" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_13"><g id="text_20"><text x="302" y="479.675" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Model docs (Markdown + Mermaid)</tspan></text></g><g id="text_21"><text x="302" y="498.95" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">generate docs — model specification with user-overridable Handlebars templates</tspan></text></g></g></g></g></g><g id="conf"><rect x="18" y="532.8" width="890" height="32.099999999999994" rx="8" fill="#fbfcfe" stroke="#2f855a" stroke-width="1.2" stroke-dasharray="6 4"/><g id="vstack_14"><g id="text_22"><text x="32" y="552.875" text-anchor="start" fill="#22543d" font-size="11.5"><tspan x="32" dy="0">5-language conformance: TS / Python / Rust / Go / PHP run the same cases against DynamoDB Local, and CI pins the results byte-identical.</tspan></text></g></g></g></g>
7
+ <g id="connector_1"><path d="M 198 235.43600000000004 C 267.01668456528756 235.43600000000004, 218.98331543471244 46.65, 288 46.65" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
8
+ <g id="connector_2"><path d="M 198 250.41800000000003 C 250.30463462938636 250.41800000000003, 235.69536537061364 119.94999999999999, 288 119.94999999999999" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_3"><path d="M 198 273.572 C 234.43950864525482 273.572, 251.56049135474518 337.54999999999995, 288 337.54999999999995" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ <g id="connector_4"><path d="M 198 285.83000000000004 C 248.83499821540272 285.83000000000004, 237.16500178459728 410.84999999999997, 288 410.84999999999997" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
11
+ <g id="connector_5"><path d="M 198 296.045 C 266.8138952001883 296.045, 219.1861047998117 484.15, 288 484.15" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
12
+ <g id="connector_6"><path d="M 598 148.6 C 598 164.44, 598 180.76, 598 196.6" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
13
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 926 582.9" width="926" height="582.9" font-family="Helvetica Neue, Arial, Hiragino Sans, sans-serif">
2
+ <defs>
3
+ <marker id="marker-filledArrow-33415c" markerWidth="7" markerHeight="7" refX="7" refY="3.5" orient="auto-start-reverse"><path d="M 0,0 L 7,3.5 L 0,7 Z" fill="#33415c"/></marker>
4
+ </defs>
5
+ <rect x="0" y="0" width="926" height="582.9" fill="#ffffff"/>
6
+ <g id="vstack_1"><g id="hstack_1"><g id="ssot"><rect x="18" y="231.35000000000002" width="180" height="68.1" rx="10" fill="#eef3fc" stroke="#2b4bab" stroke-width="1.5"/><g id="vstack_2"><g id="text_1"><text x="108" y="260.1" text-anchor="middle" fill="#1d3a8f" font-size="15" font-weight="bold"><tspan x="108" dy="0">TS Model</tspan></text></g><g id="text_2"><text x="108" y="282.425" text-anchor="middle" fill="#444444" font-size="11.5"><tspan x="108" dy="0">(SSoT — 単一の真実の源)</tspan></text></g></g></g><g id="vstack_3"><g id="rt"><rect x="288" y="18" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_4"><g id="text_3"><text x="302" y="42.175" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Runtime(TS)</tspan></text></g><g id="text_4"><text x="302" y="61.449999999999996" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">ライブ実行 — query / list / mutate / subscribe / explain</tspan></text></g></g></g><g id="ir"><rect x="288" y="91.3" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_5"><g id="text_5"><text x="302" y="115.475" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Portable IR(bridge bundle)</tspan></text></g><g id="text_6"><text x="302" y="134.75" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">manifest.json + operations.json — components[] グラフ(behavior-contracts 共通語彙)</tspan></text></g></g></g><g id="langs"><rect x="288" y="196.6" width="620" height="96.3" rx="10" fill="#f7f9fd" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_6"><g id="box_1"><rect x="288" y="196.6" width="620" height="28.799999999999997" rx="9" fill="#1d3a8f" stroke="#e5e7eb" stroke-width="0"/><g id="text_7"><text x="598" y="215.2" text-anchor="middle" fill="white" font-size="12" font-weight="bold"><tspan x="598" dy="0">生成クライアント + runtime(4言語)</tspan></text></g></g><g id="box_2"><rect x="288" y="225.39999999999998" width="620" height="67.5" fill="none" stroke="#e5e7eb" stroke-width="0"/><g id="hstack_2"><g id="py"><rect x="298" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#3776ab" stroke-width="1.8"/><g id="vstack_7"><g id="text_8"><text x="368" y="256.04999999999995" text-anchor="middle" fill="#3776ab" font-size="13" font-weight="bold"><tspan x="368" dy="0">Python</tspan></text></g><g id="text_9"><text x="368" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="368" dy="0">graphddb-runtime(PyPI)</tspan></text></g></g></g><g id="rs"><rect x="448" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#b7410e" stroke-width="1.8"/><g id="vstack_8"><g id="text_10"><text x="518" y="256.04999999999995" text-anchor="middle" fill="#b7410e" font-size="13" font-weight="bold"><tspan x="518" dy="0">Rust</tspan></text></g><g id="text_11"><text x="518" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="518" dy="0">graphddb_runtime(crates.io)</tspan></text></g></g></g><g id="go"><rect x="598" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#007d9c" stroke-width="1.8"/><g id="vstack_9"><g id="text_12"><text x="667.9999999999999" y="256.04999999999995" text-anchor="middle" fill="#007d9c" font-size="13" font-weight="bold"><tspan x="667.9999999999999" dy="0">Go</tspan></text></g><g id="text_13"><text x="668" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="668" dy="0">go module(go/vX.Y.Z tag)</tspan></text></g></g></g><g id="php"><rect x="748" y="235.39999999999998" width="140" height="47.5" rx="8" fill="white" stroke="#777bb4" stroke-width="1.8"/><g id="vstack_10"><g id="text_14"><text x="818.0000000000001" y="256.04999999999995" text-anchor="middle" fill="#777bb4" font-size="13" font-weight="bold"><tspan x="818.0000000000001" dy="0">PHP</tspan></text></g><g id="text_15"><text x="818" y="272.575" text-anchor="middle" fill="#666666" font-size="9.5"><tspan x="818" dy="0">graphddb/runtime(repo同梱)</tspan></text></g></g></g></g></g></g></g><g id="cq"><rect x="288" y="308.9" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_11"><g id="text_16"><text x="302" y="333.075" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">CQRS Contract</tspan></text></g><g id="text_17"><text x="302" y="352.34999999999997" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">public な Query / Command contract(N+1 安全・context 境界)</tspan></text></g></g></g><g id="cfn"><rect x="288" y="382.2" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_12"><g id="text_18"><text x="302" y="406.375" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">CloudFormation template</tspan></text></g><g id="text_19"><text x="302" y="425.65" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">generate cloudformation — GSI union / Streams / TTL / PITR / Auto Scaling</tspan></text></g></g></g><g id="doc"><rect x="288" y="455.5" width="620" height="57.3" rx="10" fill="white" stroke="#5886cd" stroke-width="1.5"/><g id="vstack_13"><g id="text_20"><text x="302" y="479.675" text-anchor="start" fill="#1d3a8f" font-size="13.5" font-weight="bold"><tspan x="302" dy="0">Model docs(Markdown + Mermaid)</tspan></text></g><g id="text_21"><text x="302" y="498.95" text-anchor="start" fill="#555555" font-size="11"><tspan x="302" dy="0">generate docs — Handlebars テンプレートで差し替え可能なモデル仕様書</tspan></text></g></g></g></g></g><g id="conf"><rect x="18" y="532.8" width="890" height="32.099999999999994" rx="8" fill="#fbfcfe" stroke="#2f855a" stroke-width="1.2" stroke-dasharray="6 4"/><g id="vstack_14"><g id="text_22"><text x="32" y="552.875" text-anchor="start" fill="#22543d" font-size="11.5"><tspan x="32" dy="0">5言語 conformance: TS / Python / Rust / Go / PHP が同一ケースを DynamoDB Local 実経路で実行し、結果の byte-identical を CI で固定する。</tspan></text></g></g></g></g>
7
+ <g id="connector_1"><path d="M 198 235.43600000000004 C 267.01668456528756 235.43600000000004, 218.98331543471244 46.65, 288 46.65" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
8
+ <g id="connector_2"><path d="M 198 250.41800000000003 C 250.30463462938636 250.41800000000003, 235.69536537061364 119.94999999999999, 288 119.94999999999999" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
9
+ <g id="connector_3"><path d="M 198 273.572 C 234.43950864525482 273.572, 251.56049135474518 337.54999999999995, 288 337.54999999999995" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
10
+ <g id="connector_4"><path d="M 198 285.83000000000004 C 248.83499821540272 285.83000000000004, 237.16500178459728 410.84999999999997, 288 410.84999999999997" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
11
+ <g id="connector_5"><path d="M 198 296.045 C 266.8138952001883 296.045, 219.1861047998117 484.15, 288 484.15" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
12
+ <g id="connector_6"><path d="M 598 148.6 C 598 164.44, 598 180.76, 598 196.6" fill="none" stroke="#33415c" stroke-width="2" marker-end="url(#marker-filledArrow-33415c)"/></g>
13
+ </svg>
@@ -1,19 +1,36 @@
1
- # GraphDDB Python Bridge — Multi-Language Code Generation and Runtime
1
+ # GraphDDB Multi-Language Bridge — Code Generation and Runtimes
2
2
 
3
- This document is the normative specification of GraphDDB's TypeScript-to-Python
3
+ This document is the normative specification of GraphDDB's multi-language
4
4
  bridge as implemented. TypeScript is the Single Source of Truth (SSoT): queries
5
5
  and commands are defined and validated in TypeScript, a static parameterized
6
- planner emits language-neutral JSON specifications, and `graphddb generate
7
- python` produces typed Python repositories that a thin runtime executes against
8
- DynamoDB via boto3. Python never re-implements the GraphDDB DSL; it executes the
9
- access patterns that TypeScript has already defined and validated.
6
+ planner emits language-neutral JSON specifications (the portable IR), and
7
+ `graphddb generate <python|php|rust|go>` produces typed repositories that a
8
+ thin per-language runtime executes against DynamoDB. No target language
9
+ re-implements the GraphDDB DSL; each executes the access patterns that
10
+ TypeScript has already defined and validated.
11
+
12
+ Four target languages ship today, all consuming the same bridge bundle:
13
+
14
+ | Language | Runtime package | Distribution | DynamoDB SDK | Notes |
15
+ |----------|----------------|--------------|--------------|-------|
16
+ | Python | `graphddb-runtime` | PyPI | boto3 | The worked example of §5–§7. |
17
+ | Rust | `graphddb_runtime` | crates.io | aws-sdk-dynamodb | Generated codegen-static modules need **Rust >= 1.80** (`std::sync::LazyLock`). |
18
+ | Go | `github.com/foo-log-inc/graphddb/go` | go module (`go/vX.Y.Z` tags) | aws-sdk-go-v2 | behavior-contracts is a private module dependency. |
19
+ | PHP | `graphddb/runtime` | bundled in-repo (not on composer) | aws/aws-sdk-php | Vendors the behavior-contracts PHP port (`php/src/BehaviorContracts/`). |
20
+
21
+ All four mirror the same architecture: interpret `manifest.json` /
22
+ `operations.json`, share the behavior-contracts primitives (spec-version
23
+ validation, canonical serialization, expression evaluation), and are pinned
24
+ together with the TS live executor by the 5-language conformance suite (§8).
25
+ Python is used as the worked example throughout §5–§7; the other runtimes
26
+ follow the same contract.
10
27
 
11
28
  ## 1. Scope and Principles
12
29
 
13
30
  - **TypeScript is the SSoT.** Entity, key, GSI, and relation models, together
14
31
  with the set of permitted queries and commands, are defined only in
15
- TypeScript. Python does not define entities, build ad-hoc queries, design
16
- access patterns, or resolve relations dynamically.
32
+ TypeScript. A target language does not define entities, build ad-hoc queries,
33
+ design access patterns, or resolve relations dynamically.
17
34
  - **Declarative subset only.** Only declarative, serializable definitions cross
18
35
  the bridge: parameterized keys and items, the strict select projection,
19
36
  declarative server-side filters, relation traversal, and the supported write
@@ -21,12 +38,13 @@ access patterns that TypeScript has already defined and validated.
21
38
  API is fully declarative, and any application-side post-processing is the
22
39
  caller's responsibility (`result.items.filter(...)` on the typed result),
23
40
  never bridged.
24
- - **Security boundary.** A Python caller can invoke only the queries and
41
+ - **Security boundary.** A non-TS caller can invoke only the queries and
25
42
  commands defined in TypeScript. Undefined relation traversals, Scans,
26
43
  unbounded lists, and unintended access patterns cannot be expressed.
27
44
  - **No drift by construction.** A single bridge bundle (`manifest.json` +
28
- `operations.json`) is the contract shared by every runtime, and TypeScript and
29
- Python execution semantics are pinned together by a golden conformance suite.
45
+ `operations.json`) is the contract shared by every runtime, and the execution
46
+ semantics of all five languages (TS / Python / Rust / Go / PHP) are pinned
47
+ together by a golden conformance suite.
30
48
 
31
49
  ## 2. Architecture
32
50
 
@@ -36,16 +54,16 @@ TypeScript (design-time / build-time SSoT)
36
54
  ├─ Parameterized query / command contracts (param + graphddb.publish*)
37
55
  ├─ Static parameterized planner (symbolic key evaluation)
38
56
  ├─ Bridge guard (reject non-declarative / non-serializable specs)
39
- └─ Bridge bundle: manifest.json + operations.json
40
- │ graphddb generate python
57
+ └─ Bridge bundle: manifest.json + operations.json (portable IR — components[])
58
+ │ graphddb generate <python|php|rust|go>
41
59
 
42
- Python (generated bindings + runtime)
43
- ├─ types.py (TypedDict / @dataclass result types)
44
- ├─ repositories.py (per-entity repository classes)
45
- ├─ __init__.py (re-exports)
46
- └─ graphddb_runtime (hand-written thin executor)
60
+ Generated typed bindings + hand-written thin runtime, per language
61
+ ├─ Python graphddb-runtime → boto3
62
+ ├─ Rust graphddb_runtime → aws-sdk-dynamodb
63
+ ├─ Go github.com/foo-log-inc/graphddb/go → aws-sdk-go-v2
64
+ └─ PHP graphddb/runtime → aws/aws-sdk-php
47
65
 
48
- boto3 DynamoDB client
66
+ DynamoDB
49
67
  ```
50
68
 
51
69
  | Layer | Responsibility |
@@ -53,9 +71,23 @@ boto3 DynamoDB client
53
71
  | TypeScript model | Entity / key / GSI / relation definitions |
54
72
  | Contract DSL (`param`, `graphddb.publish*`) | The permitted, parameterized queries and commands |
55
73
  | Static planner (`src/spec/*`) | Symbolic key evaluation → `manifest.json` / `operations.json` |
56
- | Generator (`src/codegen/python.ts`, `src/cli/*`) | Python repositories, result types, package exports |
57
- | Python repository | Stable application-facing interface |
58
- | Python runtime (`graphddb_runtime`) | Interprets the JSON specs and executes via boto3 |
74
+ | Generator (`src/codegen/*`, `src/cli/*`) | Typed repositories, result types, package exports per language |
75
+ | Generated repository | Stable application-facing interface |
76
+ | Language runtime | Interprets the JSON specs and executes via the language's DynamoDB SDK |
77
+
78
+ Execution itself has three permanent surfaces (issue #257): the **dynamic JSON
79
+ path** (default — load `components[]` at runtime and interpret it with the
80
+ shared `run_behavior`), the **codegen-static path** (opt-in — `graphddb
81
+ generate behaviors --lang <ts|python|go|rust|php>` bakes the same IR into
82
+ native modules through the shared upstream behavior-contracts generator, with
83
+ fingerprint-checked stale rejection), and the **typed bindings** described in
84
+ this document (`generate <python|php|rust|go>` — a consumer-UX surface that
85
+ delegates execution to the other two).
86
+
87
+ The remainder of this document uses **Python** as the worked example: §5–§7
88
+ describe the `generate python` CLI, the generated bindings, and
89
+ `graphddb-runtime` in full. The PHP / Rust / Go generators and runtimes mirror
90
+ the same bundle, validation rules, spec-version guard, and error taxonomy.
59
91
 
60
92
  ## 3. TypeScript Definition DSL
61
93
 
@@ -377,7 +409,9 @@ generated/graphddb/
377
409
  __init__.py # package re-exports
378
410
  ```
379
411
 
380
- `generate python` is the only `generate` subcommand.
412
+ `generate php` / `generate rust` / `generate go` are the sibling typed-bindings
413
+ subcommands (same bundle, same flags shape); `generate behaviors` /
414
+ `generate cloudformation` / `generate docs` serve the other surfaces.
381
415
 
382
416
  ## 5.1 Generated Python
383
417
 
@@ -625,12 +659,16 @@ them inside the handler. The deployment artifact needs the runtime package, the
625
659
  generated bindings, and the two JSON specs (boto3/botocore are provided by the
626
660
  Lambda runtime).
627
661
 
628
- ## 8. TS Python Conformance
662
+ ## 8. Cross-Language Conformance (5 languages)
629
663
 
630
- The TypeScript live executor and the Python runtime are two independent
631
- implementations of the same semantics; a golden conformance suite
632
- (`conformance/`) proves they agree. Against a shared DynamoDB Local table seeded
633
- with deterministic fixed-date data:
664
+ The TypeScript live executor and the Python / PHP / Rust / Go runtimes are five
665
+ independent implementations of the same semantics; a golden conformance suite
666
+ (`conformance/`) proves they agree. The orchestrator runs the TS path once and
667
+ compares each language runner (`py_runner.py` / `php_runner.php` /
668
+ `rust_runner` / `go_runner`) against it with the identical deep-compare — the
669
+ runners mirror one another byte-for-byte in job/result shape. The TS ↔ Python
670
+ pair below stands for all four pairings. Against a shared DynamoDB Local table
671
+ seeded with deterministic fixed-date data:
634
672
 
635
673
  - The **TypeScript path** substitutes concrete parameters into each definition's
636
674
  IR and dispatches to the live executor (`executeQuery` / `executeList` /
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphddb",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Graph data modeling on DynamoDB with adjacency list pattern",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",