graphddb 0.8.0 → 0.9.0

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.
@@ -1,4 +1,4 @@
1
- import { a1 as Param, E as ExpressionSpec, a2 as ParamKind, T as TransactionSpec, X as TransactionItemSpec } from './types-2PMXEn5x.js';
1
+ import { a3 as Param, E as ExpressionSpec, a4 as ParamKind, T as TransactionSpec, Y as TransactionItemSpec } from './types-CfxzTEFL.js';
2
2
 
3
3
  /**
4
4
  * CDC emulator types (issue #72). These types are **cdc-module-owned**; core
@@ -725,6 +725,22 @@ interface DeleteInput {
725
725
  * with `maxAttempts: 1` so the library is the single source of truth for retry
726
726
  * (documented at `graphddb.config.client` and in the README). The library does NOT
727
727
  * silently mutate a user-provided client.
728
+ *
729
+ * NOTE on the SCP Error Policy Kind (issue #292 / G9, bc `scp-error.md`):
730
+ * everything in this module is **Tuning** (max attempts / delay / backoff /
731
+ * jitter / `isRetryable`) — Runtime-owned, IR-external, Conformance-external.
732
+ * The op-level Policy **Kind** (`fail`/`retry`/`continue`) is a separate,
733
+ * IR-carried control-flow intent interpreted ONLY by behavior-contracts'
734
+ * `runPlan` (graphddb adds no Kind interpretation of its own; the runtimes
735
+ * convert a DynamoDB failure to the shared `ExecOutcome {error}` at the
736
+ * handler boundary and let `runPlan` decide). No double-retry arises today:
737
+ * this executor layer belongs to the TS live executor, which does not run
738
+ * through `runBehavior`, and the 4 spec-consumer runtimes' handlers issue SDK
739
+ * calls without a Kind-driven retry loop (bc's reference `runPlan` treats a
740
+ * persistent `retry`-Kind failure as exhausted, converging on the `fail`
741
+ * propagation). If a runtime later implements a real `retry`-Kind loop, this
742
+ * Tuning (and the SDK's own `maxAttempts`) must be treated as the INNER
743
+ * mechanism of a single logical attempt — never stacked as a second policy.
728
744
  */
729
745
  /** The single-op kind a retry is wrapping — surfaced to {@link RetryPolicy.onRetry}. */
730
746
  type RetryOperationKind = 'get' | 'query' | 'batchGet' | 'put' | 'update' | 'delete' | 'batchWrite' | 'transactWrite';
@@ -2398,6 +2414,32 @@ interface MutationEntityRef {
2398
2414
  /** The source path, e.g. `$.entity[0].postId` (documentary; surfaces in errors). */
2399
2415
  readonly path: string;
2400
2416
  }
2417
+ /**
2418
+ * The placeholder proxy handed to a mutation body as `$`. In the descriptor-map
2419
+ * authoring form (issue #108) a top-level read `$.<x>` is **ambiguous** until used:
2420
+ *
2421
+ * - `$.role` placed at a `key` / `input` leaf is an **input-field reference**
2422
+ * (a {@link MutationInputRef}, token `{role}`) — bound from the command input;
2423
+ * - `$.membership.role` is a **cross-fragment reference** — the `role` field
2424
+ * written by the fragment named `membership` (an alias). It mints an
2425
+ * {@link AliasFieldRef}, which the {@link mutation} assembler rewrites into the
2426
+ * legacy `$.entity[<index>].<field>` string the compiler resolves (the alias →
2427
+ * declaration-order index is known once every alias key is seen).
2428
+ *
2429
+ * So each top-level read returns a value that is **both** a faithful
2430
+ * {@link MutationInputRef} (when used directly as a leaf) and supports one further
2431
+ * `.<field>` access (when used as an alias root). Any other access / coercion
2432
+ * throws — the binding stays declarative (only a direct `$.field` / `$.alias.field`
2433
+ * reference or a literal is representable, never a transform).
2434
+ *
2435
+ * **Input Port 統一 (issue #264)**: this proxy is one of the three authoring
2436
+ * spellings of the SAME Input Port reference model — see the unification note
2437
+ * on {@link import('./transaction.js').ParamProxy} (`defineTransaction`'s
2438
+ * `p.*` proxy is the model; `{<field>}` templates and `{ref:["input","<field>"]}`
2439
+ * expression refs are the two serialized mirrors of one declared-input
2440
+ * namespace). Behavior here is unchanged in 0.7.x (interop kept).
2441
+ */
2442
+ type MutationInputProxy = Record<string, MutationInputRef>;
2401
2443
  declare const FRAGMENT_BRAND: unique symbol;
2402
2444
  /**
2403
2445
  * The per-field input binding of a fragment: model field name → a faithful
@@ -2406,6 +2448,14 @@ declare const FRAGMENT_BRAND: unique symbol;
2406
2448
  * field they key, never a transform.
2407
2449
  */
2408
2450
  type FragmentInput = Readonly<Record<string, MutationInputRef | string | number | boolean | Date | null>>;
2451
+ /**
2452
+ * A descriptor `key` / `input` value as authored in the descriptor-map form
2453
+ * (issue #108): a `$.field` input reference, a `$.alias.field` cross-fragment
2454
+ * reference (an opaque alias-field ref the assembler rewrites), or a literal.
2455
+ * Structurally `unknown` at the leaf because the alias-field ref is internal; the
2456
+ * assembler validates every leaf via {@link assertFaithfulInput}.
2457
+ */
2458
+ type DescriptorBinding = Readonly<Record<string, unknown>>;
2409
2459
  /** A concrete scalar admissible at a condition operand leaf. */
2410
2460
  type ConditionScalar = MutationInputRef | string | number | boolean | Date | null;
2411
2461
  /** A declarative operator object on one condition field (the #114-A subset). */
@@ -2488,6 +2538,68 @@ interface MutationFragment {
2488
2538
  * `m.create(() => Model, …)` recorder required.
2489
2539
  */
2490
2540
  type ModelRef = ModelStatic<DDBModel> | (new (...args: unknown[]) => unknown) | (() => ModelStatic<DDBModel> | (new (...args: unknown[]) => unknown));
2541
+ /**
2542
+ * One **write descriptor** in the descriptor-map authoring form (issue #108) —
2543
+ * the declarative twin of an in-process `DDBModel.mutate` entry (#101). The intent
2544
+ * key (`create` / `update` / `remove`) is the **discriminator** and carries the
2545
+ * target {@link ModelRef} (direct or thunk). The remaining fields are declarative
2546
+ * bindings (`$.field` references or literals):
2547
+ *
2548
+ * - `key` — the target row's primary-key binding (identifies the row);
2549
+ * - `input` — the non-key field binding (the body / changed fields). Optional for
2550
+ * a `remove` (a delete writes no fields);
2551
+ * - `condition` — an optional declarative write gate (issue #242, Phase 2). It is
2552
+ * the #114-A condition subset (bare equality, operator objects `{ gt }` / `{ in }`
2553
+ * / `{ between }` / …, and `and` / `or` / `not` groups) whose operand leaves are
2554
+ * `$.field` input references or literals. The declaration-DSL compiler **consumes**
2555
+ * it: each `$.field` leaf becomes a {@link import('./contract.js').ContractParamRef}
2556
+ * and the tree is attached to the compiled base op's `condition`, so it is
2557
+ * serialized (into the operation spec) and evaluated at runtime exactly as a #101
2558
+ * public write descriptor's condition is (single-op, in-process
2559
+ * transaction, and the Python bridge). A conditioned `update` / `remove` therefore
2560
+ * fails a CAS-style write when the gate does not hold, rather than silently
2561
+ * committing;
2562
+ * - `result` — an optional read-back projection `{ select, options? }` (likewise
2563
+ * accepted for authoring parity; the public read-back projection of a
2564
+ * `command(...).plan(...)` method is still declared on `command({ select })`).
2565
+ *
2566
+ * Exactly one intent key must be present.
2567
+ */
2568
+ interface WriteDescriptor {
2569
+ readonly create?: ModelRef;
2570
+ readonly update?: ModelRef;
2571
+ readonly remove?: ModelRef;
2572
+ /**
2573
+ * `upsert` — a `PutItem` with **no** `attribute_not_exists(PK)` guard (an
2574
+ * unconditional overwrite; the semantics of the removed `definePut`). Unlike
2575
+ * `create` (which always guards against clobbering an existing row), an `upsert`
2576
+ * writes whether or not the row exists; an author-supplied `condition` is honored
2577
+ * verbatim (never ANDed with a `notExists` guard).
2578
+ */
2579
+ readonly upsert?: ModelRef;
2580
+ /** The target row's primary-key binding (`{ field: $.field | literal }`). */
2581
+ readonly key: DescriptorBinding;
2582
+ /** The non-key field binding; optional (a `remove` writes no fields). */
2583
+ readonly input?: DescriptorBinding;
2584
+ /**
2585
+ * Optional declarative write gate — the #114-A condition subset (issue #242,
2586
+ * Phase 2). Compiled, serialized, and evaluated at runtime; see the interface doc.
2587
+ */
2588
+ readonly condition?: FragmentCondition;
2589
+ /** Optional read-back projection `{ select, options? }` (accepted for #101 parity). */
2590
+ readonly result?: {
2591
+ readonly select?: unknown;
2592
+ readonly options?: unknown;
2593
+ };
2594
+ /**
2595
+ * Optional custom save contract to adopt (the **whole** {@link
2596
+ * EntityWritesDefinition}). Omit to default to the target model's own `writes`.
2597
+ * Per the `use:` rule this is never a single lifecycle — the intent picks it.
2598
+ */
2599
+ readonly use?: EntityWritesDefinition;
2600
+ }
2601
+ /** The descriptor map a {@link mutation} body returns: alias → {@link WriteDescriptor}. */
2602
+ type MutationDescriptorMap = Record<string, WriteDescriptor>;
2491
2603
  declare const COMMAND_PLAN_BRAND: unique symbol;
2492
2604
  /**
2493
2605
  * The recorded **CommandPlan** — a mutation's IR (proposal §3). It carries the
@@ -2503,6 +2615,14 @@ interface CommandPlan {
2503
2615
  /** The declared write fragments, in declaration order (the mutation IR). */
2504
2616
  readonly fragments: readonly MutationFragment[];
2505
2617
  }
2618
+ /**
2619
+ * The body of a {@link mutation} in the descriptor-map authoring form (issue #108):
2620
+ * `$ => ({ alias: descriptor, … })`. It receives the placeholder proxy `$` and
2621
+ * returns an **alias → {@link WriteDescriptor}** map. The map's **insertion order**
2622
+ * is the fragments' declaration (execution) order, and each alias is the name a
2623
+ * later descriptor's `$.alias.field` cross-fragment reference resolves against.
2624
+ */
2625
+ type MutationBody = ($: MutationInputProxy) => MutationDescriptorMap;
2506
2626
 
2507
2627
  /**
2508
2628
  * Declarative transaction definition DSL (issue #46, Python-bridge Phase 4).
@@ -3260,9 +3380,10 @@ type ParamLeaf<V> = [V] extends [StringLike] ? V | string | Param<string> : V |
3260
3380
  * covariance still admits a single-member subset placeholder, while a value outside
3261
3381
  * the union / a wider placeholder / a wrong scalar kind stays a type error.
3262
3382
  */
3263
- type Parameterize<K> = [Exclude<K, Nullish>] extends [ScalarLeaf] ? [Exclude<K, Nullish>] extends [never] ? K : ParamLeaf<Exclude<K, Nullish>> | Extract<K, Nullish> : K extends object ? {
3383
+ type Parameterize<K> = [Exclude<K, Nullish>] extends [ScalarLeaf] ? [Exclude<K, Nullish>] extends [never] ? K : ParamLeaf<Exclude<K, Nullish>> | Extract<K, Nullish> : K extends object ? // An object-typed leaf (a `@map` / `@embedded` field) additionally accepts a
3384
+ {
3264
3385
  [P in keyof K]: Parameterize<K[P]>;
3265
- } : K;
3386
+ } | Param<K> : K;
3266
3387
  /** Union of all keys across every member of a (possibly union) `Real` type. */
3267
3388
  type KnownKeyOf<Real> = Real extends object ? keyof Real : never;
3268
3389
  /** The value type of key `P` across the members of a (possibly union) `Real`, non-nullable. */
@@ -3391,7 +3512,13 @@ type WriteDescriptorResultOf<D> = D extends {
3391
3512
  readonly select: infer S;
3392
3513
  };
3393
3514
  } ? S extends Record<string, unknown> ? Readonly<Record<Extract<keyof S, string>, unknown>> | null : void : void;
3394
- /** A write descriptor's contract Key (from its `key` record). */
3515
+ /**
3516
+ * A write descriptor's contract Key (from its `key` record). A #293 PUBLIC composite
3517
+ * descriptor (`{ writes, input }`) has no single top-level `key` — it is a
3518
+ * multi-entity write with no single primary Key — so it falls through to `unknown`,
3519
+ * exactly as a bare `mutation()` plan / SCP transaction body does; its public params
3520
+ * are still precise via {@link DescriptorParamsOf} (the separate `input` schema).
3521
+ */
3395
3522
  type WriteDescriptorKeyOf<D> = D extends {
3396
3523
  readonly key: infer K;
3397
3524
  } ? KeyOf<K> : unknown;
@@ -3414,7 +3541,7 @@ type ResolvedReadDescriptors<M extends ReadDescriptorMap> = QueryModelContract<M
3414
3541
  * {@link CommandPlan}, or an SCP native-syntax `defineScpTransaction(...)`
3415
3542
  * multi-write body ({@link TransactionDefinition}, Phase 4 S1 / issue #278).
3416
3543
  */
3417
- type WriteDescriptorMap = Record<string, PublicWriteDescriptor | PublicComposeDescriptor | CommandPlan | TransactionDefinition>;
3544
+ type WriteDescriptorMap = Record<string, PublicWriteDescriptor | PublicCompositeDescriptor | PublicComposeDescriptor | CommandPlan | TransactionDefinition>;
3418
3545
  /** Resolve a write-descriptor map to its {@link CommandModelContract}. */
3419
3546
  type ResolvedWriteDescriptors<M extends WriteDescriptorMap> = CommandModelContract<M[keyof M] extends infer D ? WriteDescriptorKeyOf<D> : unknown, {
3420
3547
  readonly [K in keyof M]: CommandMethodSpec<WriteDescriptorKeyOf<M[K]>, DescriptorParamsOf<M[K]>, WriteDescriptorResultOf<M[K]>>;
@@ -3493,11 +3620,33 @@ interface MutateAuthoringOptions {
3493
3620
  * `publishCommand`'s SCP-body branch — declare a mode).
3494
3621
  * - `mutate(plan, { mode })` → a {@link PublicComposeDescriptor} (`{ command,
3495
3622
  * mode }`), the closure-free composite form.
3623
+ * - `mutate(compositeDescriptor, { mode })` → the same PUBLIC composite descriptor
3624
+ * (`{ writes, input?, result? }`, issue #293) with `mode` stamped — the
3625
+ * import-free composite form usable directly as a `publishCommand` method value.
3496
3626
  */
3497
3627
  declare function mutate(body: TransactionDefinition, options?: MutateAuthoringOptions): TransactionDefinition;
3498
3628
  declare function mutate(body: CommandPlan, options?: MutateAuthoringOptions): PublicComposeDescriptor;
3499
- /** The per-call execution mode of a command method (#101): replaces `batch`. */
3500
- type CommandMode = 'transaction' | 'parallel';
3629
+ declare function mutate(body: PublicCompositeDescriptor, options?: MutateAuthoringOptions): PublicCompositeDescriptor;
3630
+ /**
3631
+ * The per-call execution mode of a command method (#101): replaces `batch`.
3632
+ *
3633
+ * `'batchWrite'` (issue #298) is the DynamoDB `BatchWriteItem` bulk form —
3634
+ * non-atomic, condition-free, any array size chunked ≤25 per request with
3635
+ * `UnprocessedItems` retry, 1×WCU — the semantics the runtime has always
3636
+ * implemented ({@link import('../runtime/command-runtime.js')}'s
3637
+ * `executeBatchWrite` machinery); #298 makes it declarable/reachable from the
3638
+ * public contract surface. It is only legal for an **unconditional** put /
3639
+ * delete (`upsert` / condition-free `remove`) — `BatchWriteItem` physically
3640
+ * carries no `ConditionExpression` and no `Update`, so a conditional / create
3641
+ * (implicit `notExists` guard) / update / derived-effect method loud-rejects it
3642
+ * at build time.
3643
+ *
3644
+ * **0.9.0 default flip ("bulk is the base case")**: an eligible method that
3645
+ * declares NO mode now defaults to `'batchWrite'` (previously `'transaction'`).
3646
+ * Declare `mode: 'transaction'` explicitly to keep the atomic
3647
+ * `TransactWriteItems` bulk form.
3648
+ */
3649
+ type CommandMode = 'transaction' | 'parallel' | 'batchWrite';
3501
3650
  /** A public **read** descriptor (issue #101): `{ query | list: Model, key, select, options? }`. */
3502
3651
  interface PublicReadDescriptor {
3503
3652
  readonly query?: ModelRef;
@@ -3567,6 +3716,54 @@ interface PublicComposeDescriptor {
3567
3716
  */
3568
3717
  readonly description?: string;
3569
3718
  }
3719
+ /**
3720
+ * A public **composite mutation** descriptor (issue #293) — the PUBLIC, closure-free
3721
+ * authoring form for a multi-entity atomic (or non-atomic) write, needing **no**
3722
+ * `mutation(...)` / `defineScpTransaction(...)` import. It carries a `writes` body
3723
+ * (`$ => ({ alias: { create|update|remove|upsert: Model, key, input?, condition? } })`
3724
+ * — the same mutation body the internal `mutation()` builder consumes), a **separate**
3725
+ * `input` schema (`{ field: param.* }`) that names the public input fields the `$`
3726
+ * proxy in the body references, an optional read-back `result.select`, and an optional
3727
+ * execution `mode`.
3728
+ *
3729
+ * `publishCommand` compiles the `writes` body internally via the retained (internal)
3730
+ * `mutation()` builder, then routes the resulting {@link CommandPlan} through the SAME
3731
+ * `buildPlannedCommandMethod` path a bare `mutation()` plan / a
3732
+ * {@link PublicComposeDescriptor} takes. A **single-alias** `writes` body is one write;
3733
+ * a **multi-alias** body is an atomic composite (promoted to one
3734
+ * `TransactWriteItems` by DynamoDB necessity — the existing promotion path), so its
3735
+ * wire is byte-identical to authoring the same composite via the internal `mutation()`.
3736
+ *
3737
+ * The `input` schema is the public param declaration: its `param.*` leaves drive the
3738
+ * generated typed binding's input struct (and the TS-level `params` type). It exists
3739
+ * separately from the body (the owner-final #293 decision) so the mutation body stays a
3740
+ * pure write declaration — options (input schema / read-back) are specified alongside it,
3741
+ * not baked into it.
3742
+ */
3743
+ interface PublicCompositeDescriptor {
3744
+ /**
3745
+ * The mutation body: `$ => ({ alias: writeDescriptor, … })`. Single alias ⇒ one
3746
+ * write; multiple aliases ⇒ an atomic composite. The `$` proxy's fields are the
3747
+ * public input fields declared in {@link input}.
3748
+ */
3749
+ readonly writes: MutationBody;
3750
+ /**
3751
+ * The public input schema: `{ field: param.* }`. Names (and types) the input fields
3752
+ * the `writes` body's `$` proxy references. Optional (a body may bind only literals),
3753
+ * though a composite normally declares at least the key params.
3754
+ */
3755
+ readonly input?: Readonly<Record<string, unknown>>;
3756
+ readonly result?: {
3757
+ readonly select?: Readonly<Record<string, boolean>>;
3758
+ readonly options?: unknown;
3759
+ };
3760
+ readonly mode?: CommandMode;
3761
+ /**
3762
+ * Optional human-readable description of the composite write use case (issue #154).
3763
+ * Pure documentation — propagated to the serialized command method spec.
3764
+ */
3765
+ readonly description?: string;
3766
+ }
3570
3767
 
3571
3768
  /**
3572
3769
  * Maintenance graph builder (Epic #118 issue #124 — the RFC B-案 core).
@@ -1,8 +1,9 @@
1
- import { L as Linter, a as LintRule } from '../linter-C-vypgut.js';
2
- export { b as LintResult } from '../linter-C-vypgut.js';
3
- import '../types-BXLzIcQD.js';
4
- import '../key-DR7_lpyk.js';
5
- import '../types-2PMXEn5x.js';
1
+ import { L as Linter, a as LintRule } from '../linter-Cr1Hnw7n.js';
2
+ export { b as LintResult } from '../linter-Cr1Hnw7n.js';
3
+ import '../types-BnFsTZwl.js';
4
+ import '../key-Dne-a20Q.js';
5
+ import '../types-CfxzTEFL.js';
6
+ import 'behavior-contracts';
6
7
 
7
8
  /**
8
9
  * Creates a Linter pre-loaded with rules safe for Entity registration.
@@ -1,4 +1,4 @@
1
- import { E as EntityMetadata } from './types-BXLzIcQD.js';
1
+ import { E as EntityMetadata } from './types-BnFsTZwl.js';
2
2
 
3
3
  declare class MetadataRegistry {
4
4
  private static store;
@@ -1,6 +1,6 @@
1
- import { E as EntityMetadata } from './types-BXLzIcQD.js';
2
- import { C as ContractSpec, Q as QuerySpec, a as CommandSpec, T as TransactionSpec, b as ContextSpec, S as SPEC_VERSION, P as ParamSpec } from './types-2PMXEn5x.js';
3
- import { Q as QueryModelContract, k as QueryMethodSpec, l as CommandModelContract, m as CommandMethodSpec } from './key-DR7_lpyk.js';
1
+ import { E as EntityMetadata } from './types-BnFsTZwl.js';
2
+ import { C as ContractSpec, Q as QuerySpec, a as CommandSpec, T as TransactionSpec, b as ContextSpec, S as SPEC_VERSION_KEY_EXPR, P as ParamSpec } from './types-CfxzTEFL.js';
3
+ import { Q as QueryModelContract, k as QueryMethodSpec, l as CommandModelContract, m as CommandMethodSpec } from './key-Dne-a20Q.js';
4
4
 
5
5
  /**
6
6
  * Contract-layer serialization (issue #59, CQRS Contract layer, Epic #57;
@@ -262,7 +262,7 @@ interface PreparedPlanSpec {
262
262
  interface PreparedPlanDocument {
263
263
  readonly formatVersion: typeof PREPARED_FORMAT_VERSION;
264
264
  /** The shared operation-IR version the plans were compiled against. */
265
- readonly specVersion: typeof SPEC_VERSION;
265
+ readonly specVersion: typeof SPEC_VERSION_KEY_EXPR;
266
266
  /** Plan id (the transform's stable call-site id) → compiled plan. */
267
267
  readonly plans: Readonly<Record<string, PreparedPlanSpec>>;
268
268
  }
@@ -1,11 +1,14 @@
1
- import { $ as AnyOperationDefinition, a0 as TransactionDefinition, b as PreparedBody } from '../key-DR7_lpyk.js';
2
- export { a1 as CompiledFragment, a2 as CompiledMutationPlan, a3 as DerivedConditionCheck, a4 as DerivedEdgeWrite, a5 as DerivedIdempotencyGuard, a6 as DerivedMaintainOutbox, a7 as DerivedMaintainWrite, a8 as DerivedOutboxEvent, a9 as DerivedUniqueGuard, aa as DerivedUpdate, ab as EntityRefResolver, ac as MAX_TRANSACT_COMPOSE_ITEMS, ad as assertNoCrossFragmentMaintainCollision, ae as compileFragment, af as compileMutationPlan, ag as compileSingleFragmentPlan, ah as resetMaintenanceGraphCache, ai as resolveLifecycle, aj as resolveMaintainers } from '../key-DR7_lpyk.js';
3
- import { M as MetadataRegistry } from '../linter-C-vypgut.js';
4
- import { C as ContractMap, e as ContextOwnershipMap, c as PreparedPlanSpec, a as PreparedPlanDocument } from '../prepared-artifact-BpPgkXEo.js';
5
- export { A as AnyModelContract, B as BuiltContracts, f as ContextOwnership, g as PREPARED_FORMAT_VERSION, h as PreparedBindMap, b as PreparedBindSpec, d as PreparedReadRouteSpec, P as PreparedWriteOpSpec, i as buildContexts, j as buildContracts, k as canonicalJson, l as entityFingerprint, p as planFingerprint } from '../prepared-artifact-BpPgkXEo.js';
6
- import { O as OperationsDocument, Q as QuerySpec, M as Manifest, C as ContractSpec, T as TransactionSpec, B as BridgeBundle, c as ConditionSpec, E as ExpressionSpec, a as CommandSpec, d as SpecVersion } from '../types-2PMXEn5x.js';
7
- export { e as CommandContractMethodSpec, f as CommandResolutionTarget, g as ComposeSpec, h as CompositionPlanSpec, b as ContextSpec, i as ContractCardinality, j as ContractCommandResult, k as ContractInputArity, l as ContractKeySpec, m as ContractKind, n as ContractResolution, o as EXPR_VERSION, p as ExecutionPlanSpec, q as ExpressionArrNode, r as ExpressionFloatNode, s as ExpressionIntNode, t as ExpressionNode, u as ExpressionObjNode, v as ExpressionOpNode, w as ExpressionOperator, x as ExpressionRefNode, y as ExpressionRefOptNode, z as ExpressionScalar, F as FilterSpec, A as ManifestEntity, D as ManifestField, G as ManifestFieldType, H as ManifestGsi, I as ManifestKey, J as ManifestRelation, K as ManifestTable, L as OperationSpec, P as ParamSpec, N as QueryContractMethodSpec, R as RangeConditionSpec, U as ReadOperationType, S as SPEC_VERSION, V as SPEC_VERSION_SCP, W as SPEC_VERSION_SUPPORTED, X as TransactionItemSpec, Y as TransactionItemType, Z as WhenSpec, _ as WriteOperationType } from '../types-2PMXEn5x.js';
8
- import '../types-BXLzIcQD.js';
1
+ import { $ as AnyOperationDefinition, a0 as TransactionDefinition, b as PreparedBody } from '../key-Dne-a20Q.js';
2
+ export { a1 as CompiledFragment, a2 as CompiledMutationPlan, a3 as DerivedConditionCheck, a4 as DerivedEdgeWrite, a5 as DerivedIdempotencyGuard, a6 as DerivedMaintainOutbox, a7 as DerivedMaintainWrite, a8 as DerivedOutboxEvent, a9 as DerivedUniqueGuard, aa as DerivedUpdate, ab as EntityRefResolver, ac as MAX_TRANSACT_COMPOSE_ITEMS, ad as assertNoCrossFragmentMaintainCollision, ae as compileFragment, af as compileMutationPlan, ag as compileSingleFragmentPlan, ah as resetMaintenanceGraphCache, ai as resolveLifecycle, aj as resolveMaintainers } from '../key-Dne-a20Q.js';
3
+ import { M as MetadataRegistry } from '../linter-Cr1Hnw7n.js';
4
+ import { B as BehaviorModelContract } from '../behaviors-DDltNivc.js';
5
+ export { a as BehaviorMethodSpec } from '../behaviors-DDltNivc.js';
6
+ import { C as ContractMap, e as ContextOwnershipMap, c as PreparedPlanSpec, a as PreparedPlanDocument } from '../prepared-artifact-BXkARxwO.js';
7
+ export { A as AnyModelContract, B as BuiltContracts, f as ContextOwnership, g as PREPARED_FORMAT_VERSION, h as PreparedBindMap, b as PreparedBindSpec, d as PreparedReadRouteSpec, P as PreparedWriteOpSpec, i as buildContexts, j as buildContracts, k as canonicalJson, l as entityFingerprint, p as planFingerprint } from '../prepared-artifact-BXkARxwO.js';
8
+ import { O as OperationsDocument, Q as QuerySpec, M as Manifest, T as TransactionSpec, C as ContractSpec, B as BridgeBundle, c as ConditionSpec, E as ExpressionSpec, a as CommandSpec, d as SpecVersion } from '../types-CfxzTEFL.js';
9
+ export { e as CommandContractMethodSpec, f as CommandResolutionTarget, g as ComposeSpec, h as CompositionPlanSpec, b as ContextSpec, i as ContractCardinality, j as ContractCommandResult, k as ContractInputArity, l as ContractKeySpec, m as ContractKind, n as ContractResolution, o as EXPR_VERSION, p as ExecutionPlanSpec, q as ExpressionArrNode, r as ExpressionFloatNode, s as ExpressionIntNode, t as ExpressionNode, u as ExpressionObjNode, v as ExpressionOpNode, w as ExpressionOperator, x as ExpressionRefNode, y as ExpressionRefOptNode, z as ExpressionScalar, F as FilterSpec, A as ManifestEntity, D as ManifestField, G as ManifestFieldType, H as ManifestGsi, I as ManifestKey, J as ManifestRelation, K as ManifestTable, L as OperationSpec, P as ParamSpec, N as QueryContractMethodSpec, R as RangeConditionSpec, U as ReadOperationType, V as SPEC_VERSION, S as SPEC_VERSION_KEY_EXPR, W as SPEC_VERSION_SCP, X as SPEC_VERSION_SUPPORTED, Y as TransactionItemSpec, Z as TransactionItemType, _ as WhenSpec, $ as WriteOperationType } from '../types-CfxzTEFL.js';
10
+ import { Component, ComponentGraphIR } from 'behavior-contracts';
11
+ import '../types-BnFsTZwl.js';
9
12
 
10
13
  /**
11
14
  * Static parameterized operation-spec generation (issue #42, Phase 0b).
@@ -33,6 +36,16 @@ interface ContractInputs {
33
36
  readonly contracts?: ContractMap;
34
37
  /** Context-ownership declarations (context → member models / contracts). */
35
38
  readonly contexts?: ContextOwnershipMap;
39
+ /**
40
+ * Resolved behavior contracts (`publishBehaviors` output, #297 SP3) — the
41
+ * shared-authoring surface registrations. ADDITIVE: each contract's bc-lowered
42
+ * components register into the emitted `components[]` as
43
+ * `<RegistrationKey>__<method>` alongside the publish* output; nothing else
44
+ * in the document changes, and an absent/empty map reproduces the previous
45
+ * bytes exactly. Their CQRS effect is purely graph-derived (there is no
46
+ * declared side to verify — see `assertPublishSplitMatchesDerived`).
47
+ */
48
+ readonly behaviors?: Readonly<Record<string, BehaviorModelContract>>;
36
49
  }
37
50
  /**
38
51
  * Build the operations document from grouped read (`queries`) and write
@@ -46,6 +59,10 @@ interface ContractInputs {
46
59
  * contract-free input (`contractInputs` empty / absent) reproduces the pre-#59
47
60
  * document byte-for-byte — no `contracts` / `contexts` keys appear.
48
61
  *
62
+ * The shared-authoring layer (#297 SP3) is likewise additive: each
63
+ * `contractInputs.behaviors` registration appends its bc-lowered components to
64
+ * `components[]` (as `<Key>__<method>`); an absent/empty map changes nothing.
65
+ *
49
66
  * @throws if a command carries a write condition outside the supported subset
50
67
  * (`{ notExists }` or pure equality) — the bridge guard; or if a contract op
51
68
  * name collides with a hand-written definition.
@@ -70,6 +87,192 @@ declare function buildOperations(queries?: Record<string, AnyOperationDefinition
70
87
  */
71
88
  declare function buildManifest(registry?: typeof MetadataRegistry): Manifest;
72
89
 
90
+ /**
91
+ * Universal component-graph IR emitter (SCP IR Phase 3, issue #290 — sub-pass 1b,
92
+ * DUAL-EMIT, behavior-contracts vocabulary v2).
93
+ *
94
+ * This module additively lifts the graphddb-specific operation IR
95
+ * (`QuerySpec.operations[]` / `TransactionSpec.items[]`, wired by `resultPath` /
96
+ * `sourceField` / `sourceList` / `{item.*}`) into the **universal SCP
97
+ * component-graph** form behavior-contracts defines
98
+ * (`scp-ir-architecture.md` §5/§5.1, `ts/src/behavior.ts`): a `Component{ name,
99
+ * inputPorts, body[], output, plan }` whose `body` nodes are `componentRef` /
100
+ * `map` referencing the graphddb catalog (`GetItem` / `Query` / `BatchGetItem` /
101
+ * `PutItem` / `UpdateItem` / `DeleteItem` / `ConditionCheck`) and whose Port
102
+ * wiring is Expression IR.
103
+ *
104
+ * ## SP5 ownership split (#297 / bc#26)
105
+ *
106
+ * Since #297 SP5 this module EXTRACTS but does not ASSEMBLE: every derived
107
+ * graph (node ids, ports, map/into/batched decisions, relationKind, plan) is
108
+ * handed to behavior-contracts' data-registration builder
109
+ * (`buildComponentDefinition`, validated against `GRAPHDDB_CATALOG`), which
110
+ * owns the IR shape — structural/catalog/plan validation, reference-root
111
+ * existence, and the deterministic code-point key-sorted canonicalization of
112
+ * the final `Component`. graphddb's `assertComponentsInCatalog` stays as the
113
+ * stricter consumer-side gate on top (its dynamic-family whitelist is tighter
114
+ * than the builder's `additionalPorts` acceptance — belt-and-suspenders by
115
+ * design).
116
+ *
117
+ * ## Dual-emit (this sub-pass only)
118
+ *
119
+ * The emitted `components[]` sits ALONGSIDE the existing
120
+ * `queries`/`commands`/`transactions` — nothing here removes or rewrites the old
121
+ * wiring. The 4 spec-consumer runtimes (py/php/rust/go) keep reading the OLD path
122
+ * (`queries` etc.); `components[]` is a new top-level field they tolerate (they
123
+ * read only the keys they know, and `validateEnvelope` checks only `version`).
124
+ * The purpose of the additive emit is to PROVE, via behavior-contracts
125
+ * `assertPortableComponentGraph` + `runBehavior`, that the universal form is
126
+ * well-formed and semantically reproduces the query — de-risking the later
127
+ * sub-passes that migrate the runtimes onto it.
128
+ *
129
+ * ## Vocabulary v2 (bc#22, behaviorVersion 2) — the sub-pass-2a gap closures
130
+ *
131
+ * The 2a escalation proved 6 constructs the sub-pass-1 emission could not carry;
132
+ * this emitter closes them on the v2 map vocabulary:
133
+ *
134
+ * 1. **Depth-2+ relations** (`$.groups.items.group[.permissions.items]`): a
135
+ * relation whose producer is a CONNECTION is emitted as a `map` over the
136
+ * parent connection's `items` with `into: <relationProp>` (zip-attach onto the
137
+ * per-element membership row); deeper levels CHAIN over the previous map's
138
+ * augmented list (`over: {ref:[<prevMapId>]}`), reading the parent body
139
+ * through the attach key (`{ref:["$el","group",…]}`). The attach is FLAT on
140
+ * the element (v2 `into` semantics — the canonical bc depth-2 vector shape);
141
+ * the node id carries the full `resultPath`-derived path
142
+ * (`groups.items.group.permissions.items`), so re-nesting the flat key into
143
+ * the old assembled placement (`item.group.permissions`) is a mechanical,
144
+ * id-driven fold in the consuming runtime.
145
+ * 2. **Per-element transaction guards**: the legacy `when:{op,left,right}`
146
+ * comparison AND the #267/#268 `guard` Expression IR both lower to `map.when`
147
+ * (evaluated under the `$item` element binding; strict-bool, fail-closed).
148
+ * 3. **Write-condition / write-item ports completeness**: every transaction
149
+ * item's `entity`, `condition` (all kinds), `literalKey` and `maintain`
150
+ * payload are carried as ports, so a handler builds the exact TransactWrite
151
+ * item from the evaluated ports alone (plus its injected manifest/config —
152
+ * the C4 boundary; no node-identity join needed).
153
+ * 4. **Relation filters**: an op's `filter.declarative` tree rides in the read
154
+ * ports (JSON-encoded — see below).
155
+ * 5. **Implicit-strip marker**: a `refs` fan-out whose driver list was projected
156
+ * only implicitly (`sourceList.implicit`) emits `implicitSourceField` in its
157
+ * map ports, so the post-assembly strip of the driver field from the parent
158
+ * is expressible without the old `sourceList`.
159
+ * 6. **Batched fan-out**: fan-outs the old path serves with ONE deduped/chunked
160
+ * `BatchGetItem` (a `sourceList` refs fan-out; a belongsTo child of a
161
+ * connection) emit `batched: true` — the handler receives `{items:[…]}` once
162
+ * and owns dedupe/chunk/retry (CONSUMER), returning a list aligned to
163
+ * `items`. Per-element `GetItem`/`Query` maps stay unbatched.
164
+ *
165
+ * ## Opaque-JSON ports (declarative trees)
166
+ *
167
+ * A port VALUE is Expression IR: `assertPortableComponentGraph` walks every port
168
+ * value through the closed operator set, so a declarative operator tree
169
+ * (`filter.declarative`, `condition.declarative`, `condition.names`, `maintain`)
170
+ * — whose single-key nodes (`{and:…}`, `{name:…}`) would be mis-read as
171
+ * unknown operators — is carried as a **canonical JSON string literal**
172
+ * (deterministically key-sorted), which the handler parses. Caller-param leaves
173
+ * (`{$param}`) that such a tree binds at execution time are lifted OUT into
174
+ * companion `condition.params.<name>` / `condition.values.<slot>` ports whose
175
+ * values are `{ref:[<param>]}` — evaluated by the executor, so the handler gets
176
+ * the bound values without reaching into graphddb scope internals.
177
+ *
178
+ * ## Scope convention (`runBehavior`-native)
179
+ *
180
+ * The graphddb Phase-2 key wiring roots its Expression IR references at
181
+ * `input.<param>` / `result.<field>` (and guards at `item.<field>`). The
182
+ * universal `runBehavior` executor evaluates ports against a FLAT scope
183
+ * `{ ...input, ...nodeResultsById, [<as>]: element }`, so this emitter REMAPS
184
+ * the scope roots when lowering:
185
+ *
186
+ * - `["input", p]` → `[p]` — a param at the top-level scope.
187
+ * - `["result", f]` → `[<parentNodeId>, f]` — the parent node result, or
188
+ * `["$el"(…attach segs), f]` inside a relation map, or `[<as>, f]` inside a
189
+ * refs fan-out map.
190
+ * - `["item", f]` → `["$item", f]` — a forEach guard's element field.
191
+ *
192
+ * The remap is a pure rename of the reference ROOTS; the literal/`concat`
193
+ * structure the Phase-2 lowerer produced is reused verbatim.
194
+ *
195
+ * ## Cardinality-one root collapse
196
+ *
197
+ * A cardinality-`'one'` query whose root is a `Query` (unique-GSI lookup)
198
+ * assembles, on the old path, a SINGLE entity (first matched item) that child
199
+ * relations key off (`{result.userId}`). Expression IR has no list indexing, so
200
+ * the collapse is carried as a root port `cardinality: 'one'` — the catalog
201
+ * `Query` handler returns the first matched item (or null) instead of a
202
+ * connection, exactly the old runtime's root shaping.
203
+ */
204
+
205
+ /**
206
+ * Lower one {@link QuerySpec} into a universal SCP {@link Component}. Each read
207
+ * {@link OperationSpec} becomes a body node:
208
+ *
209
+ * - the root op (`resultPath === '$'`) → a `componentRef` whose ports carry the
210
+ * remapped `keyExpr` (rooted at the params) and `projection`; a
211
+ * cardinality-one Query root adds the `cardinality: 'one'` collapse port;
212
+ * - a `refs` fan-out op (carrying `sourceList`) → a **batched** `map` node
213
+ * iterating the parent list attribute (`sourceList.over`), the per-element key
214
+ * bound through the `sourceList.as` element binding, with the
215
+ * `implicitSourceField` strip marker when the driver list was implicit;
216
+ * - a relation whose producer is a CONNECTION (or a deeper link of such a
217
+ * chain) → a `map` over the connection's items / the previous map's augmented
218
+ * list, `into: <relationProp>` (zip-attach; `batched` when the old path served
219
+ * it with one BatchGetItem);
220
+ * - a root-level `hasMany` / `belongsTo` relation → a `componentRef` with
221
+ * `parent`, `bindField` (the source field for null-binding skip), and
222
+ * `relationKind`.
223
+ *
224
+ * The component's `output` is the Φ merge: the root node result with each
225
+ * ROOT-LEVEL relation attached under its property; a chained connection exposes
226
+ * `{obj:{cursor:<connection cursor>, items:<final augmented list>}}`. The `plan`
227
+ * is re-derived from the emitted parent wiring (identical `{groups,
228
+ * concurrency}` shape; equal to the query's plan wherever chaining introduced no
229
+ * new dependency), or absent for a single-node read.
230
+ */
231
+ declare function buildQueryComponent(name: string, query: QuerySpec): Component;
232
+ /**
233
+ * Lower one {@link TransactionSpec} into a universal SCP {@link Component}. A
234
+ * transaction is a single-stage batched write; each item becomes a body node:
235
+ *
236
+ * - a `forEach` item (expanded once per element of the named array param) → an
237
+ * SCP `map` over that array param (`over: {ref:[<source>]}`, `as: "$item"`),
238
+ * its `{item.<field>}` template tokens lowered to `["$item", field]` refs and
239
+ * its `when`/`guard` lowered to `map.when` (gap 2 — a falsy element is
240
+ * skipped: handler not called, excluded from the result, order preserved);
241
+ * - a plain item with an input-scope `guard` → a MAP OF ONE with `when`
242
+ * (`over: {arr:[true]}`), reproducing the old kept/skipped expansion;
243
+ * - a plain item → a `componentRef` against the params.
244
+ *
245
+ * The `component` name is the DynamoDB write catalog entry (`Put` → `PutItem`,
246
+ * `Update` → `UpdateItem`, `Delete` → `DeleteItem`, `ConditionCheck` →
247
+ * `ConditionCheck`). The output is the array of every item node's result (a
248
+ * transaction returns no per-item image, so this is descriptive of the writes).
249
+ */
250
+ declare function buildTransactionComponent(name: string, tx: TransactionSpec): Component;
251
+ /**
252
+ * Build the universal `components[]` for a whole operations document (dual-emit,
253
+ * issue #290 sub-pass 1b). Every query and every transaction is lifted into one
254
+ * {@link Component}; commands (single writes) are represented via the query
255
+ * readbacks / transactions already present, so this sub-pass lifts the two
256
+ * multi-node forms (queries, transactions) that exercise the universal `map` /
257
+ * `componentRef` / plan vocabulary. Deterministic: queries then transactions,
258
+ * each in sorted-name order.
259
+ *
260
+ * Every emitted component is validated against {@link GRAPHDDB_CATALOG}
261
+ * (#297 SP1c — names, required ports, declared-port families); a mismatch
262
+ * throws, so an emitter drift from the catalog is a BUILD error, never a
263
+ * silently-shipped document.
264
+ */
265
+ declare function buildComponents(queries: Readonly<Record<string, QuerySpec>>, transactions: Readonly<Record<string, TransactionSpec>>): Component[];
266
+ /**
267
+ * Wrap emitted `components[]` into the portable component-graph IR document
268
+ * (`{irVersion, exprVersion, components}` — scp-ir-architecture.md §5): the
269
+ * ONLY input shape behavior-contracts' common Generator accepts (issue #257 —
270
+ * `generateModule` loudly rejects the raw operations bundle / internal IR).
271
+ * graphddb adds no generation logic: this envelope is the entire consumer-side
272
+ * input contract of the upstream codegen-static endpoint (§7.3 endpoint 3).
273
+ */
274
+ declare function portableIrDocument(components: readonly Component[]): ComponentGraphIR;
275
+
73
276
  /**
74
277
  * N+1 static checker for the CQRS Contract layer (issue #60, Epic #57; proposal
75
278
  * `docs/cqrs-contract.md`, "N+1 Safety (Static Restriction)").
@@ -394,24 +597,22 @@ declare function assertBundleSerializable(bundle: BridgeBundle): void;
394
597
  */
395
598
  declare function canonicalizeExpressionSpec(input: unknown, context: string): ExpressionSpec;
396
599
  /**
397
- * Does this operations-document content actually contain an SCP Expression IR
398
- * node — a `{ kind: 'scpExpr' }` write condition or a `guard` (transaction
399
- * item / contract command method)? This is the **presence scan** behind the
400
- * conditional stamp (issue #261): the walk visits exactly the slots the spec
401
- * vocabulary defines, so an SCP-free document is provably stamped `1.1` and
402
- * stays byte-identical.
600
+ * The spec version to stamp on an operations document. **SCP IR Phase 2 (#289):
601
+ * always `2.0`.** The read-op key wiring moved from `{param}` string templates to
602
+ * the portable Expression IR (`keyExpr` / `valueExpr`), a MAJOR IR serialization
603
+ * change so the whole operations IR moves to `2.0` at once (migration plan §4).
604
+ * A pre-#289 runtime (supported `1.2`) `validateEnvelope`-rejects a `2.0`
605
+ * document, the intended breaking cut. The former conditional `1.1`/`1.2`
606
+ * presence-scan stamping (issue #261, `operationsContainScpNodes`) was removed
607
+ * in the final #290 sub-pass: every `2.0` document is a superset (guard/scpExpr
608
+ * nodes still validate under exprVersion 2), so a single unconditional `2.0`
609
+ * stamp is correct now that the read-op key wiring is unconditionally Expression
610
+ * IR.
403
611
  */
404
- declare function operationsContainScpNodes(doc: {
612
+ declare function operationsSpecVersion(_doc: {
405
613
  readonly commands: Readonly<Record<string, CommandSpec>>;
406
- readonly transactions?: Readonly<Record<string, TransactionSpec>>;
407
614
  readonly contracts?: Readonly<Record<string, ContractSpec>>;
408
- }): boolean;
409
- /**
410
- * The spec version to stamp on an operations document: `1.2` iff it actually
411
- * contains an SCP node ({@link operationsContainScpNodes}), else the base
412
- * `1.1` — so every pre-#261 bundle serializes byte-identically.
413
- */
414
- declare function operationsSpecVersion(doc: Parameters<typeof operationsContainScpNodes>[0]): SpecVersion;
615
+ }): SpecVersion;
415
616
 
416
617
  /**
417
618
  * Static prepared-plan artifact — the **build-time** (AOT) compilation of
@@ -503,4 +704,4 @@ declare function buildPreparedPlanDocument(plans: Readonly<Record<string, Prepar
503
704
  */
504
705
  declare function buildBridgeBundle(queries?: Record<string, AnyOperationDefinition>, commands?: Record<string, AnyOperationDefinition>, registry?: typeof MetadataRegistry, transactions?: Record<string, TransactionDefinition>, contractInputs?: ContractInputs): BridgeBundle;
505
706
 
506
- export { BridgeBundle, CommandSpec, ConditionSpec, ContextOwnershipMap, type ContractBoundaryViolation, type ContractInputs, ContractMap, type ContractN1Violation, ContractSpec, ExpressionSpec, Manifest, OperationsDocument, PreparedPlanDocument, PreparedPlanSpec, QuerySpec, SpecVersion, TransactionSpec, assertBundleSerializable, assertContractBoundaries, assertContractN1Safe, assertJsonSerializable, assertSupportedCondition, buildBridgeBundle, buildManifest, buildOperations, buildPreparedPlanDocument, buildQuerySpec, buildTransactionSpec, buildTransactions, canonicalizeExpressionSpec, collectContractBoundaryViolations, collectContractN1Violations, compilePreparedPlan, operationsContainScpNodes, operationsSpecVersion };
707
+ export { BehaviorModelContract, BridgeBundle, CommandSpec, ConditionSpec, ContextOwnershipMap, type ContractBoundaryViolation, type ContractInputs, ContractMap, type ContractN1Violation, ContractSpec, ExpressionSpec, Manifest, OperationsDocument, PreparedPlanDocument, PreparedPlanSpec, QuerySpec, SpecVersion, TransactionSpec, assertBundleSerializable, assertContractBoundaries, assertContractN1Safe, assertJsonSerializable, assertSupportedCondition, buildBridgeBundle, buildComponents, buildManifest, buildOperations, buildPreparedPlanDocument, buildQueryComponent, buildQuerySpec, buildTransactionComponent, buildTransactionSpec, buildTransactions, canonicalizeExpressionSpec, collectContractBoundaryViolations, collectContractN1Violations, compilePreparedPlan, operationsSpecVersion, portableIrDocument };