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 +89 -40
- package/docs/diagrams/execution-paths.en.svg +14 -0
- package/docs/diagrams/execution-paths.ja.svg +14 -0
- package/docs/diagrams/query-pipeline.en.svg +10 -0
- package/docs/diagrams/query-pipeline.ja.svg +10 -0
- package/docs/diagrams/ssot-derivation.en.svg +13 -0
- package/docs/diagrams/ssot-derivation.ja.svg +13 -0
- package/docs/python-bridge.md +66 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,41 +1,63 @@
|
|
|
1
1
|
# GraphDDB
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Portable, contract-first DynamoDB access patterns.**
|
|
4
4
|
|
|
5
|
-
GraphDDB
|
|
6
|
-
|
|
7
|
-
It is not an ORM
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
- ✅ **
|
|
15
|
-
- ✅ **
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- ✅ **
|
|
20
|
-
- ✅ **
|
|
21
|
-
- ✅ **
|
|
22
|
-
- ✅ **
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
- **
|
|
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
|
|
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
|
-
|
|
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
|
+

|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
308
|
+

|
|
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
|
+

|
|
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 <ts|python|go|rust|php></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 <ts|python|go|rust|php></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>
|
package/docs/python-bridge.md
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
|
-
# GraphDDB
|
|
1
|
+
# GraphDDB Multi-Language Bridge — Code Generation and Runtimes
|
|
2
2
|
|
|
3
|
-
This document is the normative specification of GraphDDB's
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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.
|
|
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
|
|
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
|
|
29
|
-
|
|
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
|
-
|
|
43
|
-
├─
|
|
44
|
-
├─
|
|
45
|
-
├─
|
|
46
|
-
└─
|
|
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
|
-
|
|
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
|
|
57
|
-
|
|
|
58
|
-
|
|
|
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
|
|
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.
|
|
662
|
+
## 8. Cross-Language Conformance (5 languages)
|
|
629
663
|
|
|
630
|
-
The TypeScript live executor and the Python
|
|
631
|
-
implementations of the same semantics; a golden conformance suite
|
|
632
|
-
(`conformance/`) proves they agree.
|
|
633
|
-
|
|
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` /
|