graphddb 0.3.1 → 0.4.1

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.
@@ -227,6 +227,16 @@ interface Param<out T> {
227
227
  * `{item.<field>}` templates. `undefined` for scalar params.
228
228
  */
229
229
  readonly element?: Readonly<Record<string, Param<unknown>>>;
230
+ /**
231
+ * Optional human-readable description of the parameter (issue #154), supplied
232
+ * via `param.string({ description })` etc. Pure documentation metadata — it does
233
+ * NOT affect the runtime descriptor (`kind` / `literals`) the planner reads for
234
+ * execution. When present it is propagated to the param's {@link
235
+ * import('./ir.js').ParamDescriptor} and then to the serialized
236
+ * {@link import('../spec/types.js').ParamSpec} in `operations.json`. Absent →
237
+ * unchanged output (backward compatible).
238
+ */
239
+ readonly description?: string;
230
240
  }
231
241
  /** A `Param` whose represented value type is `string`. */
232
242
  type StringParam = Param<string>;
@@ -249,26 +259,41 @@ type ArrayParam<E extends ArrayElementShape> = Param<ElementOf<E>[]> & {
249
259
  };
250
260
  /** Allowed scalar value types a placeholder may stand in for. */
251
261
  type ParamValue = string | number;
262
+ /**
263
+ * Options accepted by the placeholder factories (issue #154). Currently carries
264
+ * only the optional human-readable {@link Param.description} — pure documentation
265
+ * metadata that does not affect the runtime descriptor. The object form is
266
+ * additive: `param.string()` (no options) is unchanged.
267
+ */
268
+ interface ParamOptions {
269
+ /** Optional human-readable description, propagated to `operations.json`. */
270
+ readonly description?: string;
271
+ }
252
272
  /**
253
273
  * Placeholder factory. Each call returns a branded {@link Param} carrying both
254
- * the TypeScript value type and a runtime descriptor.
274
+ * the TypeScript value type and a runtime descriptor. Each scalar factory accepts
275
+ * an optional {@link ParamOptions} (issue #154) carrying a `description` — pure
276
+ * documentation propagated to `operations.json`; the no-argument call is unchanged.
255
277
  */
256
278
  declare const param: {
257
279
  /** A placeholder for a `string` value. */
258
- readonly string: () => StringParam;
280
+ readonly string: (options?: ParamOptions) => StringParam;
259
281
  /** A placeholder for a `number` value. */
260
- readonly number: () => NumberParam;
282
+ readonly number: (options?: ParamOptions) => NumberParam;
261
283
  /**
262
284
  * A placeholder constrained to one of the given literal values. The value
263
285
  * type of the resulting {@link Param} is the **union of the literals**, so it
264
- * is preserved precisely in the IR and the inferred definition types.
286
+ * is preserved precisely in the IR and the inferred definition types. A final
287
+ * plain-object argument is read as {@link ParamOptions} (a `description`),
288
+ * distinguished from the `string` / `number` literal values.
265
289
  *
266
290
  * @example
267
291
  * ```ts
268
292
  * param.literal('active', 'disabled'); // Param<'active' | 'disabled'>
293
+ * param.literal('active', 'disabled', { description: 'Account state.' });
269
294
  * ```
270
295
  */
271
- readonly literal: <const L extends readonly [ParamValue, ...ParamValue[]]>(...values: L) => LiteralParam<L[number]>;
296
+ readonly literal: <const L extends readonly [ParamValue, ...ParamValue[]]>(...valuesAndOptions: [...L] | [...L, ParamOptions]) => LiteralParam<L[number]>;
272
297
  /**
273
298
  * A placeholder for an **array** parameter whose elements have the given field
274
299
  * shape. Used by `defineTransaction`'s `tx.forEach(p.<arrayParam>, …)` to bind
@@ -280,7 +305,7 @@ declare const param: {
280
305
  * // Param<{ userId: string; role: string }[]>
281
306
  * ```
282
307
  */
283
- readonly array: <const E extends ArrayElementShape>(element: E) => ArrayParam<E>;
308
+ readonly array: <const E extends ArrayElementShape>(element: E, options?: ParamOptions) => ArrayParam<E>;
284
309
  };
285
310
  /** Runtime type guard: is `value` a parameter placeholder? */
286
311
  declare function isParam(value: unknown): value is Param<unknown>;
@@ -1765,6 +1790,21 @@ interface ConditionTree {
1765
1790
  interface WriteDefinitionOptions {
1766
1791
  /** Optional declarative write condition (subset). */
1767
1792
  readonly condition?: ConditionInput;
1793
+ /**
1794
+ * Optional human-readable description of the command use case (issue #154). Pure
1795
+ * documentation — propagated to `operations.json` and the generated Python
1796
+ * repository-method docstring. Omit for unchanged output.
1797
+ */
1798
+ readonly description?: string;
1799
+ }
1800
+ /** Options accepted by the read `define*` entry points (issue #154). */
1801
+ interface ReadDefinitionOptions {
1802
+ /**
1803
+ * Optional human-readable description of the query use case (issue #154). Pure
1804
+ * documentation — propagated to `operations.json` and the generated Python
1805
+ * repository-method docstring. Omit for unchanged output.
1806
+ */
1807
+ readonly description?: string;
1768
1808
  }
1769
1809
  /**
1770
1810
  * Identifies the entity an operation targets. `name` is the model class name
@@ -1790,6 +1830,13 @@ interface ParamDescriptor<T = unknown> {
1790
1830
  * descriptors. `undefined` for scalar params.
1791
1831
  */
1792
1832
  readonly element?: Readonly<Record<string, ParamDescriptor>>;
1833
+ /**
1834
+ * Optional human-readable description of the parameter (issue #154), carried
1835
+ * from a `param.*({ description })` placeholder. Pure documentation — it does
1836
+ * not affect `kind` / `literals` (the execution-relevant descriptor). Propagated
1837
+ * to the serialized {@link import('../spec/types.js').ParamSpec}.
1838
+ */
1839
+ readonly description?: string;
1793
1840
  /** Parameters are always required (no optional params in this phase). */
1794
1841
  readonly required: true;
1795
1842
  }
@@ -1843,6 +1890,15 @@ interface OperationDefinition<T extends DDBModel, Op extends OperationKind, K, S
1843
1890
  * when no condition is attached or for reads (issue #46).
1844
1891
  */
1845
1892
  readonly condition?: ConditionInput;
1893
+ /**
1894
+ * Optional human-readable description of the definition (issue #154), supplied
1895
+ * via the entry-point options (`defineQuery(..., { description })` etc.). Pure
1896
+ * documentation — propagated to the serialized {@link
1897
+ * import('../spec/types.js').QuerySpec.description} /
1898
+ * {@link import('../spec/types.js').CommandSpec.description} and to the generated
1899
+ * Python repository-method docstring. It does not affect execution.
1900
+ */
1901
+ readonly description?: string;
1846
1902
  /** Collected parameters: name → descriptor (value type preserved in `P`). */
1847
1903
  readonly params: P;
1848
1904
  /** @internal Phantom carrier so the entity type `T` is retained on the node. */
@@ -2057,7 +2113,17 @@ type ProjectionMap = Readonly<Record<string, ProjectionTransform>>;
2057
2113
  * @param n The preview length bound (a positive integer).
2058
2114
  * @throws if `n` is not a positive integer.
2059
2115
  */
2060
- declare function preview(path: EffectPath, n: number): ProjectionTransform;
2116
+ /**
2117
+ * A value position the projection helpers accept: either a literal path string or
2118
+ * a symbolic `source.<field>` reference (a `{ path }` carrier — the `SourceRef` the
2119
+ * `@maintainedFrom` / versioned `(self, source) =>` callbacks mint, issue #152).
2120
+ * Typed structurally (no import) so `entity-writes` stays free of a back-edge to
2121
+ * the decorator layer; the symbolic ref's branded type still flows through.
2122
+ */
2123
+ type PathLike = EffectPath | {
2124
+ readonly path: EffectPath;
2125
+ };
2126
+ declare function preview(path: PathLike, n: number): ProjectionTransform;
2061
2127
  /**
2062
2128
  * Standalone authoring helper for an `identity` {@link ProjectionTransform}: copy
2063
2129
  * the source `path` through unchanged. The recorder-free counterpart to
@@ -2069,7 +2135,7 @@ declare function preview(path: EffectPath, n: number): ProjectionTransform;
2069
2135
  *
2070
2136
  * @param path The source value copied through unchanged.
2071
2137
  */
2072
- declare function identity(path: EffectPath): ProjectionTransform;
2138
+ declare function identity(path: PathLike): ProjectionTransform;
2073
2139
  /**
2074
2140
  * The **path** a maintenance write travels (shared vocabulary, epic #118 A/B
2075
2141
  * reconciliation — RFC §5.1 / issue #121 are the authority). `mutation` lands the
@@ -2752,446 +2818,72 @@ declare function mutation(name: string, body: MutationBody): CommandPlan;
2752
2818
  declare const definePlan: typeof mutation;
2753
2819
 
2754
2820
  /**
2755
- * `defineView` / `defineProjection` the maintained **view** and **external
2756
- * projection** definition DSL (Epic #118 Phase 2, issue #132 child M).
2757
- *
2758
- * ## Where this sits in the `define*` family
2759
- *
2760
- * This module extends the record-of-definitions pattern of
2761
- * `src/define/define.ts` (`defineQuery`/`defineList`/… grouped by
2762
- * `defineQueries`/`defineCommands`) with two new families that declare a single
2763
- * **view** node → IR:
2764
- *
2765
- * - {@link defineView} (`materializedView`) — declares an INDEPENDENT view row
2766
- * maintained from the lifecycle events of one or more **source** entities. The
2767
- * view row is its OWN modelled row (a `DDBModel` with its own `keys`), NOT a
2768
- * field of any source entity — the "特定エンティティのフィールドでない単体行" of
2769
- * RFC §5.3. RFC §5.3:
2770
- * ```ts
2771
- * defineView(UserThreadListModel, {
2772
- * pattern: 'materializedView',
2773
- * source: [{ entity: () => PostModel, maintainedOn: ['Post.created'], … }, …],
2774
- * keys: { userId: '$.entity.userId' },
2775
- * fields: { … }, // per-source projection of the view row
2776
- * write: { updateMode: 'stream' },
2777
- * })
2778
- * ```
2779
- * - {@link defineProjection} (`externalProjection`) — declares a stream + idempotency
2780
- * projection of a source entity into an EXTERNAL sink (BigQuery / S3 / OpenSearch
2781
- * in production; the CDC emulator in dev/test). RFC §5.3:
2782
- * ```ts
2783
- * defineProjection('TestCaseResultBQ', {
2784
- * pattern: 'externalProjection',
2785
- * source: () => TestCaseResultModel,
2786
- * via: 'stream',
2787
- * idempotencyKey: 'resultId',
2788
- * })
2789
- * ```
2790
- *
2791
- * `defineViews({...})` / `defineProjections({...})` take a record of these
2792
- * definition nodes and return the same record (typed), forming the IR the
2793
- * maintenance graph (#124, extended here as the third maintenance source after
2794
- * relations and aggregates) and the projection sink consume — exactly the
2795
- * `defineQueries`/`defineCommands`样式.
2796
- *
2797
- * ## Why a view is its own definition (not a relation `@hasMany`)
2798
- *
2799
- * A relation/aggregate maintainer (#124) hangs off a MODELLED entity row — its
2800
- * destination is a `DDBModel` class resolved by the relation owner, and its
2801
- * single source is the relation's `to`. A **materialized view** is the
2802
- * complementary case the RFC §5.3 calls out: an independent row fed by SEVERAL
2803
- * foreign sources (none of which is the view itself). So it cannot be a relation
2804
- * decorator on a source; it is its own top-level declaration whose destination is
2805
- * the dedicated **view model** row. That view model is a normal `DDBModel` (so the
2806
- * maintenance graph / drain / rebuild resolve its key with the SAME machinery they
2807
- * use for a relation owner — no parallel key system), but it is the owner of NO
2808
- * relation: the sources point INTO it, declared here rather than on the sources.
2809
- *
2810
- * ## Scope boundary (payload-同梱; multi-source as per-source slices)
2811
- *
2812
- * Each `source` projects ONLY from its own payload (the same payload-同梱 rule
2813
- * the relation maintenance graph enforces — RFC §4.A.6 `requiredContext` /
2814
- * write-time-fetch is a deferred follow-up). A multi-source view is therefore
2815
- * maintained as a UNION of per-source slices on one view row: `Post.created`
2816
- * updates the Post-projected `fields`, `Thread.read` updates the Thread-projected
2817
- * `fields`, each converging the shared view row through the K (#130) stream →
2818
- * outbox → drain path. A field whose value must combine attributes from more than
2819
- * one source in a single write (a cross-source join at maintenance time) is the
2820
- * `requiredContext` case and is out of scope — see the module-level note and the
2821
- * issue report.
2822
- */
2823
-
2824
- type AnyModelClass = abstract new (...args: any[]) => DDBModel;
2825
- /** A source-entity factory: a model class or a `ModelStatic` wrapper. */
2826
- type SourceFactory = () => AnyModelClass | ModelStatic<DDBModel>;
2827
- /** A bare-string identity shorthand or an explicit `w.transform(...)` IR node. */
2828
- type ProjectionEntry = ProjectionTransform | string;
2829
- /**
2830
- * Build a {@link MembershipPredicate} for a sparse view (Epic #118 pattern 6 / #133).
2831
- * The view row is PUT when the predicate holds and DELETED when it flips false. The
2832
- * `path` is normalized to a payload-rooted source value (a bare field name becomes
2833
- * `$.entity.<field>`).
2821
+ * Decorator-metadata maintenance-graph `ViewDefinition` adapter (issue #152).
2834
2822
  *
2835
- * Named `whenMember` (not `when`) to avoid colliding with the transaction-condition
2836
- * `when` helper (`src/define/transaction.ts`).
2823
+ * ## What this replaces
2837
2824
  *
2838
- * @example `whenMember('status', 'eq', 'active')` the view row exists only while
2839
- * `status === 'active'`.
2840
- * @example `whenMember('archived', 'falsy')` the view row exists only while
2841
- * `archived` is falsy.
2842
- */
2843
- declare function whenMember(field: string, op: MembershipPredicateOp, value?: unknown): MembershipPredicate;
2844
- /**
2845
- * One source contributing to a maintained view (issue #132). The source entity's
2846
- * lifecycle events ({@link maintainedOn}) drive the maintenance; its payload is
2847
- * projected into the view row's {@link fields} (payload-同梱). When the source
2848
- * maintains an ordered/bounded slice (a collection-shaped view) it declares
2849
- * {@link collection}; otherwise it maintains a single snapshot slice.
2850
- */
2851
- interface ViewSource {
2852
- /** Resolves the source entity whose lifecycle drives this slice of the view. */
2853
- readonly entity: SourceFactory;
2854
- /**
2855
- * The cross-entity triggers this source fires on (`'<Entity>.<event>'`, the
2856
- * shared `created`/`updated`/`removed` vocabulary). The entity segment must be
2857
- * the source entity's logical name (the maintenance graph validates it).
2858
- */
2859
- readonly maintainedOn: readonly string[];
2860
- /**
2861
- * The view-row key binding for THIS source: view-row key field → a path-rooted
2862
- * source value (`$.entity.<field>` / `$.input.<field>`). Resolves which view
2863
- * row this source event maintains. When omitted, the view-level {@link
2864
- * ViewDefinitionInput.keys} is used (the common case every source keys the
2865
- * view row the same way).
2866
- */
2867
- readonly keys?: Readonly<Record<string, EffectPath>>;
2868
- /**
2869
- * The projection of THIS source's payload into the view row (target attribute →
2870
- * identity shorthand string / `w.transform(...)`). When omitted, the view-level
2871
- * {@link ViewDefinitionInput.fields} is used.
2872
- */
2873
- readonly fields?: Readonly<Record<string, ProjectionEntry>>;
2874
- /**
2875
- * Declares this source maintains a bounded, ordered COLLECTION slice of the view
2876
- * row (e.g. "latest N posts") rather than a single snapshot. The `field` names
2877
- * the view-row attribute holding the list; `maxItems` / `order` shape it.
2878
- */
2879
- readonly collection?: {
2880
- readonly field: string;
2881
- readonly maxItems?: number;
2882
- readonly order?: 'ASC' | 'DESC';
2883
- /** The source path the collection orders by + trims on (e.g. `$.entity.createdAt`). */
2884
- readonly orderBy?: EffectPath;
2885
- };
2886
- /**
2887
- * Sparse-view predicate (Epic #118 pattern 6 / #133): when present, this source
2888
- * maintains a MEMBERSHIP slice — the view row is PUT (projected) while the predicate
2889
- * holds and DELETED when it flips false (and always deleted on a source `removed`).
2890
- * Build it with {@link whenMember} (e.g. `whenMember('status', 'eq', 'active')`). Mutually
2891
- * exclusive with {@link collection} (a row either appears/disappears or holds a list).
2892
- */
2893
- readonly when?: MembershipPredicate;
2894
- }
2895
- /** The author-facing input to {@link defineView}. */
2896
- interface ViewDefinitionInput {
2897
- /** The maintenance preset — `'materializedView'` (snapshot/collection) or `'sparseView'` (membership). */
2898
- readonly pattern?: 'materializedView' | 'sparseView';
2899
- /** One or more sources whose lifecycle events maintain the view row. */
2900
- readonly source: ViewSource | readonly ViewSource[];
2901
- /**
2902
- * The default view-row key binding (view-row key field → path-rooted source
2903
- * value). A source may override it with its own `keys`. At least one of the
2904
- * view-level `keys` or every source's `keys` must be present.
2905
- */
2906
- readonly keys?: Readonly<Record<string, EffectPath>>;
2907
- /** The default per-source projection of the view row (source may override). */
2908
- readonly fields?: Readonly<Record<string, ProjectionEntry>>;
2909
- /** Maintenance-write declaration shared by the sources (`updateMode` / `consistency`). */
2910
- readonly write?: {
2911
- readonly updateMode?: MaintainUpdateMode;
2912
- readonly consistency?: MaintainConsistency;
2913
- };
2914
- }
2915
- /** Marks an object as a {@link ViewDefinition} IR node. */
2916
- declare const VIEW_DEFINITION_MARKER: unique symbol;
2917
- /**
2918
- * The global registry of declared {@link ViewDefinition}s (issue #132). A
2919
- * `defineView(...)` registers itself here so the compile-side global maintenance
2920
- * graph (and the linter) discovers view maintainers WITHOUT the caller threading
2921
- * the definitions through — the same way `@model` auto-registers an entity in
2922
- * `MetadataRegistry`. A {@link generation} counter (bumped on every register /
2923
- * clear) lets a cache keyed off it invalidate when a view is added, so a
2924
- * newly-declared view is never silently dropped from the compile path.
2925
- */
2926
- declare class ViewRegistry {
2927
- private static readonly views;
2928
- private static gen;
2929
- /** Register (or replace, by view class) a declared view. Bumps the generation. */
2930
- static register(def: ViewDefinition): void;
2931
- /** Every registered view, in declaration order. */
2932
- static getAll(): readonly ViewDefinition[];
2933
- /** The monotonic generation counter (changes whenever the set of views changes). */
2934
- static get generation(): number;
2935
- /** Forget every registered view (test reset). Bumps the generation. */
2936
- static clear(): void;
2937
- }
2938
- /**
2939
- * The lowered per-source maintenance slice of a view — one entry per (source ×
2940
- * trigger), carrying the resolved source class, the validated triggers, the view
2941
- * row key binding, and the projection. Consumed by the maintenance graph (#124)
2942
- * which synthesizes the A-defined `SnapshotEffect` / `CollectionEffect` from it.
2825
+ * The old `defineView` / `defineVersioned` builders (deleted) registered
2826
+ * `ViewDefinition`s into a side `ViewRegistry`, which the maintenance graph read.
2827
+ * That builder carried a registration side-effect + a `generation` counter (a
2828
+ * silent-drop guard). This adapter removes that whole path: it derives the SAME
2829
+ * `ViewDefinition` IR purely from the declarative `MetadataRegistry` — the
2830
+ * Contract-layer SSoT, whose own `generation` counter is the single
2831
+ * invalidation source — so a view declared via `@model({ kind })` + `@maintainedFrom`
2832
+ * (and a versioned relation declared via `@hasOne/@hasMany` `pattern`) is discovered
2833
+ * with no separate registry.
2834
+ *
2835
+ * ## IR invariance
2836
+ *
2837
+ * The `ViewDefinition` / `ViewSourceSlice` shapes are UNCHANGED. The maintenance
2838
+ * graph, the K (#130) stream/drain, and the L (#131) rebuild consume the adapter's
2839
+ * output exactly as they consumed `ViewRegistry.getAll()`. Only the SOURCE of the
2840
+ * definitions moved from a builder side-effect to declarative metadata.
2841
+ *
2842
+ * ## Order independence (issue #152 hardening)
2843
+ *
2844
+ * Stacked `@maintainedFrom` declarations carry no order meaning. The adapter rejects
2845
+ * — symmetrically, so the error is identical whichever order the decorators are
2846
+ * stacked — any two declarations on the same view that:
2847
+ * 1. write the SAME projection target attribute (ambiguous duplicate projection);
2848
+ * 2. maintain the SAME `collection.field`;
2849
+ * 3. bind the SAME view-key field to a DIFFERENT source path (the view-row identity
2850
+ * would be inconsistent across sources).
2851
+ * A legitimate multi-source view (different sources filling DIFFERENT fields, all
2852
+ * binding the SAME key the SAME way) is fine.
2943
2853
  */
2854
+
2855
+ type AnyModelClass = abstract new (...args: any[]) => any;
2856
+ /** The view source slice IR the maintenance graph consumes (one per source × view). */
2944
2857
  interface ViewSourceSlice {
2945
- /** The resolved source model class (the lifecycle origin / projected payload). */
2946
2858
  readonly sourceClass: AnyModelClass;
2947
- /** The validated triggers this slice fires on. */
2948
2859
  readonly maintainedOn: readonly MaintainTrigger[];
2949
- /** The view-row key binding (view-row key field → path-rooted source value). */
2950
2860
  readonly keys: Readonly<Record<string, EffectPath>>;
2951
- /** The projection map (target attribute → `w.transform(...)` IR). */
2952
2861
  readonly project: ProjectionMap;
2953
- /** Bounded/ordered collection options when this slice maintains a list. */
2954
2862
  readonly collection?: {
2955
2863
  readonly field: string;
2956
2864
  readonly maxItems?: number;
2957
2865
  readonly orderBy?: EffectPath;
2958
2866
  readonly orderDir?: 'ASC' | 'DESC';
2959
2867
  };
2960
- /**
2961
- * Sparse-view membership predicate (Epic #118 pattern 6 / #133) when this slice
2962
- * maintains a put/delete membership row. The maintenance graph synthesizes a
2963
- * `MembershipEffect` (not a snapshot) from it.
2964
- */
2965
2868
  readonly predicate?: MembershipPredicate;
2966
2869
  }
2967
- /**
2968
- * The IR for one `defineView` node — an independent materialized-view row
2969
- * maintained from one or more source entities. The `name` is the view's logical
2970
- * identity; `viewClass` is the dedicated view model the row lives on (the
2971
- * maintenance destination); `slices` are the lowered per-source maintenance
2972
- * contributions the maintenance graph turns into effects.
2973
- */
2870
+ /** The view definition IR — an independent view row maintained from one or more sources. */
2974
2871
  interface ViewDefinition {
2975
- readonly [VIEW_DEFINITION_MARKER]: true;
2976
- /** The view's logical name (e.g. `'UserThreadList'`). */
2977
2872
  readonly name: string;
2978
- /** The dedicated view model class the maintained row lives on (the destination). */
2979
2873
  readonly viewClass: AnyModelClass;
2980
- /** The maintenance preset (`'materializedView'` or `'sparseView'`). */
2981
2874
  readonly pattern: 'materializedView' | 'sparseView';
2982
- /** The lowered per-source maintenance slices. */
2983
2875
  readonly slices: readonly ViewSourceSlice[];
2984
- /** The path the maintenance writes travel (`mutation` / `stream`). */
2985
- readonly updateMode?: MaintainUpdateMode;
2986
- /** The consistency the maintenance writes land under. */
2987
- readonly consistency?: MaintainConsistency;
2988
- }
2989
- /** Runtime guard: is `value` a {@link ViewDefinition}? */
2990
- declare function isViewDefinition(value: unknown): value is ViewDefinition;
2991
- /**
2992
- * Define a single maintained **view** (`materializedView`, issue #132): an
2993
- * independent view row (on the dedicated `view` model) maintained from one or more
2994
- * source entities' lifecycle events, projecting each source's payload (payload-同梱)
2995
- * into the view row. The returned {@link ViewDefinition} is the IR the maintenance
2996
- * graph (#124) consumes as a third maintenance source (after relations /
2997
- * aggregates), so a view row converges through the SAME stream → outbox → drain
2998
- * path (K, #130).
2999
- *
3000
- * @param view The dedicated view model class the maintained row lives on (a normal
3001
- * `DDBModel` with its own `keys`). Its logical name is the view's `name`.
3002
- * @param input The view's sources / key binding / projection / write declaration.
3003
- *
3004
- * @example
3005
- * ```ts
3006
- * const UserThreadList = defineView(UserThreadListModel, {
3007
- * pattern: 'materializedView',
3008
- * keys: { userId: '$.entity.userId' },
3009
- * source: [
3010
- * { entity: () => PostModel, maintainedOn: ['Post.created'],
3011
- * fields: { lastPostId: 'postId', lastPostAt: 'createdAt' } },
3012
- * { entity: () => ThreadModel, maintainedOn: ['Thread.updated'],
3013
- * fields: { threadTitle: 'title' } },
3014
- * ],
3015
- * write: { updateMode: 'stream' },
3016
- * });
3017
- * ```
3018
- */
3019
- declare function defineView(view: AnyModelClass | ModelStatic<DDBModel>, input: ViewDefinitionInput): ViewDefinition;
3020
- /** A record of view-name → {@link ViewDefinition}. */
3021
- type ViewDefinitionMap = Record<string, ViewDefinition>;
3022
- /**
3023
- * Group a record of {@link defineView} nodes into the view IR consumed by the
3024
- * maintenance graph (#124). Validates that every entry is a `defineView` node —
3025
- * the `defineQueries`/`defineCommands` 様式.
3026
- */
3027
- declare function defineViews<const D extends ViewDefinitionMap>(definitions: D): D;
3028
- /** The author-facing input to {@link defineVersioned}. */
3029
- interface VersionedDefinitionInput {
3030
- /** The maintenance preset — `'versioned'`. */
3031
- readonly pattern?: 'versioned';
3032
- /** Resolves the source entity whose lifecycle events maintain both rows. */
3033
- readonly source: SourceFactory;
3034
- /**
3035
- * The triggers that maintain a new version (`'<Entity>.<event>'`). Typically
3036
- * `['Doc.created', 'Doc.updated']` — every persisted revision advances the latest
3037
- * pointer and appends a history row.
3038
- */
3039
- readonly maintainedOn: readonly string[];
3040
- /**
3041
- * The LATEST-pointer row's key binding (latest-model key field → path-rooted source
3042
- * value). It must NOT include the version discriminator — the latest row is
3043
- * OVERWRITTEN on each revision (one row per source identity, e.g. `{ docId:
3044
- * '$.entity.docId' }`).
3045
- */
3046
- readonly latestKeys: Readonly<Record<string, EffectPath>>;
3047
- /**
3048
- * The HISTORY row's key binding (history-model key field → path-rooted source value).
3049
- * It MUST include the version discriminator so each revision is a NEW row (append-only
3050
- * history, e.g. `{ docId: '$.entity.docId', version: '$.entity.version' }`).
3051
- */
3052
- readonly historyKeys: Readonly<Record<string, EffectPath>>;
3053
- /** The projection of the source payload into BOTH rows (target attribute → source). */
3054
- readonly fields: Readonly<Record<string, ProjectionEntry>>;
3055
- /** Maintenance-write declaration shared by both rows (`updateMode` / `consistency`). */
3056
- readonly write?: {
3057
- readonly updateMode?: MaintainUpdateMode;
3058
- readonly consistency?: MaintainConsistency;
3059
- };
3060
- }
3061
- /**
3062
- * The pair of {@link ViewDefinition}s a {@link defineVersioned} lowers to — the
3063
- * latest-pointer snapshot row and the append-only history snapshot row.
3064
- */
3065
- interface VersionedDefinition {
3066
- /** The LATEST-pointer row (a snapshot, overwritten on each revision). */
3067
- readonly latest: ViewDefinition;
3068
- /** The append-only HISTORY row (one snapshot row per version). */
3069
- readonly history: ViewDefinition;
3070
- }
3071
- /**
3072
- * Define a **versioned / latest-pointer** maintained access path (Epic #118 pattern 8,
3073
- * issue #133): from one source revision, maintain a LATEST-pointer row (overwritten in
3074
- * place) AND append a HISTORY row (one per version) in a single composed write.
3075
- *
3076
- * ## Lowering = composition of two snapshot effects (no new effect)
3077
- *
3078
- * Per the design hint "既存の snapshot(latest)+ 別行追記(history)の合成で表現できるか",
3079
- * `versioned` is **pure composition** of the existing {@link SnapshotEffect}:
3080
- *
3081
- * - the LATEST row is a snapshot keyed by the source identity WITHOUT the version
3082
- * (`latestKeys`) → re-projecting the same key OVERWRITES the pointer in place;
3083
- * - the HISTORY row is a snapshot keyed by the source identity PLUS the version
3084
- * (`historyKeys`) → each revision resolves a NEW row, so history is append-only.
3085
- *
3086
- * Both are lowered as {@link defineView} (`materializedView`) nodes — the maintenance
3087
- * graph synthesizes a `SnapshotEffect` per source trigger, and because the two rows
3088
- * resolve to DIFFERENT destination rows (distinct models / keys) the same-row collision
3089
- * guard is satisfied and BOTH fire from the one source mutation: the latest pointer and
3090
- * the history row land together (in one atomic tx for `updateMode: 'mutation'`, or
3091
- * converge through the stream → drain path for `'stream'`). There is NO new maintenance
3092
- * primitive — the existing snapshot pipeline (sync #127 / stream #130 / rebuild #131)
3093
- * carries both.
3094
- *
3095
- * @param latest The dedicated LATEST-pointer view model (one row per source identity).
3096
- * @param history The dedicated HISTORY view model (one row per version).
3097
- * @param input The source / triggers / key bindings / projection / write declaration.
3098
- *
3099
- * @example
3100
- * ```ts
3101
- * const DocVersioned = defineVersioned(DocLatestModel, DocVersionModel, {
3102
- * pattern: 'versioned',
3103
- * source: () => DocModel,
3104
- * maintainedOn: ['Doc.created', 'Doc.updated'],
3105
- * latestKeys: { docId: '$.entity.docId' },
3106
- * historyKeys: { docId: '$.entity.docId', version: '$.entity.version' },
3107
- * fields: { docId: 'docId', version: 'version', title: 'title' },
3108
- * write: { updateMode: 'mutation' },
3109
- * });
3110
- * ```
3111
- */
3112
- declare function defineVersioned(latest: AnyModelClass | ModelStatic<DDBModel>, history: AnyModelClass | ModelStatic<DDBModel>, input: VersionedDefinitionInput): VersionedDefinition;
3113
- /** Marks an object as a {@link ProjectionDefinition} IR node. */
3114
- declare const PROJECTION_DEFINITION_MARKER: unique symbol;
3115
- /** The transport a projection travels — only `stream` (async) in this phase. */
3116
- type ProjectionVia = 'stream';
3117
- /** The author-facing input to {@link defineProjection}. */
3118
- interface ProjectionDefinitionInput {
3119
- /** The maintenance preset — `'externalProjection'`. */
3120
- readonly pattern?: 'externalProjection';
3121
- /** Resolves the source entity whose lifecycle events are projected to the sink. */
3122
- readonly source: SourceFactory;
3123
- /** The transport (`'stream'` — async CDC; the only supported value this phase). */
3124
- readonly via?: ProjectionVia;
3125
- /**
3126
- * The source attribute whose value is the **idempotency key** for at-least-once
3127
- * de-duplication at the sink (e.g. `'resultId'`). A redelivered source event
3128
- * with the same key is folded to one sink upsert.
3129
- */
3130
- readonly idempotencyKey: string;
3131
- /**
3132
- * The lifecycle events projected. Defaults to every event of the source
3133
- * (`created` / `updated` / `removed`) when omitted.
3134
- */
3135
- readonly on?: readonly ('created' | 'updated' | 'removed')[];
3136
- /**
3137
- * Optional projection of the source payload into the sink record (target
3138
- * attribute → identity shorthand / transform). When omitted the whole source
3139
- * `newImage` is projected.
3140
- */
3141
- readonly fields?: Readonly<Record<string, ProjectionEntry>>;
3142
- }
3143
- /**
3144
- * The IR for one `defineProjection` node — a stream + idempotency projection of a
3145
- * source entity into an external sink. Consumed by the projection sink runtime
3146
- * ({@link import('../cdc/projection-sink.js')}), which subscribes to
3147
- * the CDC stream and upserts the projected record into the sink, folding
3148
- * at-least-once delivery by {@link idempotencyKey}.
3149
- */
3150
- interface ProjectionDefinition {
3151
- readonly [PROJECTION_DEFINITION_MARKER]: true;
3152
- /** The projection's logical name (e.g. `'TestCaseResultBQ'`). */
3153
- readonly name: string;
3154
- /** The maintenance preset (always `'externalProjection'`). */
3155
- readonly pattern: 'externalProjection';
3156
- /** The resolved source model class whose events are projected. */
3157
- readonly sourceClass: AnyModelClass;
3158
- /** The transport (`'stream'`). */
3159
- readonly via: ProjectionVia;
3160
- /** The source attribute used as the idempotency key at the sink. */
3161
- readonly idempotencyKey: string;
3162
- /** The lifecycle events projected (defaults to all three). */
3163
- readonly on: readonly ('created' | 'updated' | 'removed')[];
3164
- /** The optional projection map (target attribute → transform IR); empty = whole image. */
3165
- readonly project: ProjectionMap;
2876
+ readonly updateMode?: 'mutation' | 'stream';
2877
+ readonly consistency?: 'transactional' | 'eventual';
3166
2878
  }
3167
- /** Runtime guard: is `value` a {@link ProjectionDefinition}? */
3168
- declare function isProjectionDefinition(value: unknown): value is ProjectionDefinition;
3169
2879
  /**
3170
- * Define a single **external projection** (`externalProjection`, issue #132): a
3171
- * stream + idempotency projection of a source entity into an external sink
3172
- * (BigQuery / S3 / OpenSearch in production; the CDC emulator + an in-process sink
3173
- * in dev/test). At-least-once delivery is folded to one sink upsert per genuine
3174
- * source event by the {@link ProjectionDefinitionInput.idempotencyKey}.
2880
+ * Build every {@link ViewDefinition} for a registry from `@model({ kind })` +
2881
+ * `@maintainedFrom` view models AND from versioned-pattern relations. This is the
2882
+ * adapter the maintenance graph calls in place of the deleted `ViewRegistry.getAll()`.
3175
2883
  *
3176
- * @example
3177
- * ```ts
3178
- * const TestCaseResultBQ = defineProjection('TestCaseResultBQ', {
3179
- * pattern: 'externalProjection',
3180
- * source: () => TestCaseResultModel,
3181
- * via: 'stream',
3182
- * idempotencyKey: 'resultId',
3183
- * });
3184
- * ```
3185
- */
3186
- declare function defineProjection(name: string, input: ProjectionDefinitionInput): ProjectionDefinition;
3187
- /** A record of projection-name → {@link ProjectionDefinition}. */
3188
- type ProjectionDefinitionMap = Record<string, ProjectionDefinition>;
3189
- /**
3190
- * Group a record of {@link defineProjection} nodes into the projection IR consumed
3191
- * by the projection sink runtime. Validates every entry is a `defineProjection`
3192
- * node — the `defineQueries`/`defineCommands` 様式.
2884
+ * @param registry The models to scan. Defaults to `MetadataRegistry.getAll()`.
3193
2885
  */
3194
- declare function defineProjections<const D extends ProjectionDefinitionMap>(definitions: D): D;
2886
+ declare function collectViewDefinitions(registry?: ReadonlyMap<Function, EntityMetadata>): ViewDefinition[];
3195
2887
 
3196
2888
  /**
3197
2889
  * Maintenance graph builder (Epic #118 issue #124 — the RFC B-案 core).
@@ -3387,6 +3079,13 @@ interface ManifestField {
3387
3079
  * mirroring the TS hydrator's `format`-driven `Date` reconstruction.
3388
3080
  */
3389
3081
  readonly format?: 'datetime' | 'date';
3082
+ /**
3083
+ * Optional human-readable description of the field (issue #154), from a field
3084
+ * decorator option (`@string({ description })`). Pure documentation — absent
3085
+ * unless declared, so a field with no description serializes byte-identically
3086
+ * to the pre-#154 manifest. Surfaces as a field comment in the generated Python.
3087
+ */
3088
+ readonly description?: string;
3390
3089
  }
3391
3090
  /** A key (PK or GSI) template descriptor in the manifest. */
3392
3091
  interface ManifestKey {
@@ -3420,6 +3119,13 @@ interface ManifestEntity {
3420
3119
  readonly key: ManifestKey | null;
3421
3120
  readonly gsis: readonly ManifestGsi[];
3422
3121
  readonly relations: Readonly<Record<string, ManifestRelation>>;
3122
+ /**
3123
+ * Optional human-readable description of the entity (issue #154), from
3124
+ * `@model({ description })`. Pure documentation — absent unless declared, so an
3125
+ * entity with no description serializes byte-identically to the pre-#154
3126
+ * manifest. Surfaces as the generated Python class docstring.
3127
+ */
3128
+ readonly description?: string;
3423
3129
  }
3424
3130
  interface ManifestTable {
3425
3131
  readonly physicalName: string;
@@ -3439,6 +3145,13 @@ interface ParamSpec {
3439
3145
  * descriptors (field name → element param spec). Omitted for scalar params.
3440
3146
  */
3441
3147
  readonly element?: Readonly<Record<string, ParamSpec>>;
3148
+ /**
3149
+ * Optional human-readable description of the parameter (issue #154), from a
3150
+ * `param.*({ description })` placeholder. Pure documentation — absent unless
3151
+ * declared, so a param with no description serializes byte-identically to the
3152
+ * pre-#154 spec. The Python runtime never reads it for execution.
3153
+ */
3154
+ readonly description?: string;
3442
3155
  }
3443
3156
  /** A `begins_with` range condition on a sort key (templated value). */
3444
3157
  interface RangeConditionSpec {
@@ -3547,6 +3260,13 @@ interface QuerySpec {
3547
3260
  * backward-compatible (plan-absent → sequential) fallback.
3548
3261
  */
3549
3262
  readonly executionPlan?: ExecutionPlanSpec;
3263
+ /**
3264
+ * Optional human-readable description of the query (issue #154), from
3265
+ * `defineQuery(..., { description })`. Pure documentation — absent unless
3266
+ * declared, so a query with no description serializes byte-identically to the
3267
+ * pre-#154 spec. Surfaces as the generated Python repository-method docstring.
3268
+ */
3269
+ readonly description?: string;
3550
3270
  }
3551
3271
  type WriteOperationType = 'PutItem' | 'UpdateItem' | 'DeleteItem';
3552
3272
  /**
@@ -3624,6 +3344,14 @@ interface CommandSpec {
3624
3344
  readonly changes?: Readonly<Record<string, string>>;
3625
3345
  /** Optional write condition (subset). */
3626
3346
  readonly condition?: ConditionSpec;
3347
+ /**
3348
+ * Optional human-readable description of the command (issue #154), from
3349
+ * `definePut`/`defineUpdate`/`defineDelete(..., { description })`. Pure
3350
+ * documentation — absent unless declared, so a command with no description
3351
+ * serializes byte-identically to the pre-#154 spec. Surfaces as the generated
3352
+ * Python repository-method docstring.
3353
+ */
3354
+ readonly description?: string;
3627
3355
  }
3628
3356
  /**
3629
3357
  * A declarative `when` guard on a transaction item (issue #46). Compares a
@@ -3974,6 +3702,14 @@ interface QueryContractMethodSpec {
3974
3702
  * call (chunk ≤100). Absent → resolve compositions sequentially (pre-#70).
3975
3703
  */
3976
3704
  readonly compositionPlan?: CompositionPlanSpec;
3705
+ /**
3706
+ * Optional human-readable description of the read use case (issue #154), from the
3707
+ * descriptor's `description`. Pure documentation — absent unless declared, so a
3708
+ * method with no description serializes byte-identically to the pre-#154 spec.
3709
+ * The same string appears in the TS contract IR and (via the SSoT) in any
3710
+ * generated binding, so TS↔Python carry an identical description.
3711
+ */
3712
+ readonly description?: string;
3977
3713
  }
3978
3714
  /**
3979
3715
  * How a contract command method resolves a single key vs. an array of keys to the
@@ -4040,6 +3776,12 @@ interface CommandContractMethodSpec {
4040
3776
  * {@link result} stays `'void'` / `'entity'` and it returns no projected item).
4041
3777
  */
4042
3778
  readonly returnSelection?: Readonly<Record<string, boolean>>;
3779
+ /**
3780
+ * Optional human-readable description of the write use case (issue #154), from
3781
+ * the descriptor's `description`. Pure documentation — absent unless declared, so
3782
+ * a method with no description serializes byte-identically to the pre-#154 spec.
3783
+ */
3784
+ readonly description?: string;
4043
3785
  }
4044
3786
  /**
4045
3787
  * A serialized contract — a keyed public read (`'query'`) or write (`'command'`)
@@ -5085,6 +4827,13 @@ interface ContractMethodOp<Op extends OperationKind = OperationKind> {
5085
4827
  * when the body declares no composition.
5086
4828
  */
5087
4829
  readonly compose?: readonly RecordedCompose[];
4830
+ /**
4831
+ * Optional human-readable description of the use case (issue #154), captured from
4832
+ * the descriptor's `description`. Pure documentation — carried on the op so the
4833
+ * serializer can emit it onto the contract method spec; it never affects the
4834
+ * recorded operation, key, or runtime behaviour.
4835
+ */
4836
+ readonly description?: string;
5088
4837
  }
5089
4838
  /**
5090
4839
  * A recorded External Query composition edge on a contract method op (#63). The
@@ -5167,6 +4916,12 @@ interface QueryMethodSpec<TKey, TParams, TResult, A extends InputArity = InputAr
5167
4916
  * the referenced contract name by identity ({@link contractOfMethodSpec}).
5168
4917
  */
5169
4918
  readonly __methodName?: string;
4919
+ /**
4920
+ * Optional human-readable description of the use case (issue #154), from the
4921
+ * descriptor's `description`. Pure documentation — propagated to the serialized
4922
+ * {@link import('../spec/types.js').QueryContractMethodSpec.description}.
4923
+ */
4924
+ readonly description?: string;
5170
4925
  /** @internal Phantom carrier retaining the formal `QueryMethod` type. */
5171
4926
  readonly __signature?: QueryMethod<TKey, TParams, TResult>;
5172
4927
  }
@@ -5319,6 +5074,12 @@ interface CommandMethodSpec<TKey, TParams, TResult> {
5319
5074
  * at least one stream maintainer; absent otherwise (no regression).
5320
5075
  */
5321
5076
  readonly maintainOutbox?: readonly DerivedMaintainOutbox[];
5077
+ /**
5078
+ * Optional human-readable description of the write use case (issue #154), from
5079
+ * the descriptor's `description`. Pure documentation — propagated to the
5080
+ * serialized {@link import('../spec/types.js').CommandContractMethodSpec.description}.
5081
+ */
5082
+ readonly description?: string;
5322
5083
  /** @internal Phantom carrier retaining the formal `CommandMethod` type. */
5323
5084
  readonly __signature?: CommandMethod<TKey, TParams, TResult>;
5324
5085
  }
@@ -5521,6 +5282,13 @@ interface PublicReadDescriptor {
5521
5282
  readonly key: Readonly<Record<string, unknown>>;
5522
5283
  readonly select: Readonly<Record<string, unknown>>;
5523
5284
  readonly options?: Readonly<Record<string, unknown>>;
5285
+ /**
5286
+ * Optional human-readable description of the read use case (issue #154). Pure
5287
+ * documentation — propagated to the serialized {@link
5288
+ * import('../spec/types.js').QueryContractMethodSpec.description} in
5289
+ * `operations.json`. Omit for unchanged output.
5290
+ */
5291
+ readonly description?: string;
5524
5292
  }
5525
5293
  /** A public **write** descriptor (issue #101): `{ create | update | remove: Model, key, input?, condition?, result?, mode? }`. */
5526
5294
  interface PublicWriteDescriptor {
@@ -5535,6 +5303,13 @@ interface PublicWriteDescriptor {
5535
5303
  readonly options?: unknown;
5536
5304
  };
5537
5305
  readonly mode?: CommandMode;
5306
+ /**
5307
+ * Optional human-readable description of the write use case (issue #154). Pure
5308
+ * documentation — propagated to the serialized {@link
5309
+ * import('../spec/types.js').CommandContractMethodSpec.description} in
5310
+ * `operations.json`. Omit for unchanged output.
5311
+ */
5312
+ readonly description?: string;
5538
5313
  }
5539
5314
  /**
5540
5315
  * A public **composite write** descriptor (issue #101) — the closure-free twin of
@@ -5552,6 +5327,12 @@ interface PublicComposeDescriptor {
5552
5327
  readonly options?: unknown;
5553
5328
  };
5554
5329
  readonly mode?: CommandMode;
5330
+ /**
5331
+ * Optional human-readable description of the composite write use case (issue
5332
+ * #154). Pure documentation — propagated to the serialized {@link
5333
+ * import('../spec/types.js').CommandContractMethodSpec.description}.
5334
+ */
5335
+ readonly description?: string;
5555
5336
  }
5556
5337
 
5557
5338
  /**
@@ -6424,6 +6205,15 @@ interface FieldOptions {
6424
6205
  readonly?: boolean;
6425
6206
  serialize?: (value: unknown) => unknown;
6426
6207
  deserialize?: (value: unknown) => unknown;
6208
+ /**
6209
+ * Optional human-readable description of the field (issue #154). Pure
6210
+ * documentation metadata — it does NOT affect storage, hydration, key handling,
6211
+ * or any runtime behaviour. When present it is propagated to the field entry in
6212
+ * `manifest.json` ({@link ManifestField.description}) and surfaces as a field
6213
+ * comment in the generated Python `types.py`. Absent → byte-for-byte unchanged
6214
+ * output (backward compatible).
6215
+ */
6216
+ description?: string;
6427
6217
  }
6428
6218
  interface FieldMetadata {
6429
6219
  propertyName: string;
@@ -6442,6 +6232,49 @@ interface FieldMetadata {
6442
6232
  literals?: readonly string[];
6443
6233
  }
6444
6234
 
6235
+ /**
6236
+ * The maintenance kind of a model (issue #152). `'entity'` (the default) is a plain
6237
+ * stored entity. `'materializedView'` / `'sparseView'` mark a model as a maintained
6238
+ * **view** row whose `@maintainedFrom` declarations feed the maintenance graph (the
6239
+ * adapter that replaces the old `defineView` / `ViewRegistry` path). A `sparseView`
6240
+ * requires every `@maintainedFrom` to carry a `when` membership predicate.
6241
+ */
6242
+ type ModelKind = 'entity' | 'materializedView' | 'sparseView';
6243
+ /**
6244
+ * One lowered `@maintainedFrom(source, (self, source) => options)` declaration on a
6245
+ * view model (issue #152). It is the decorator-declarative replacement for one
6246
+ * `defineView` source slice: the symbolic `(self, source) =>` callback has already
6247
+ * been evaluated into the SAME payload-rooted IR (`keyBind` → `$.entity.*` key
6248
+ * binding, `project` → {@link ProjectionMap}), so the adapter
6249
+ * (`src/relation/maintenance-view-adapter.ts`) reconstructs a byte-identical
6250
+ * `ViewSourceSlice` from it.
6251
+ *
6252
+ * `collection` and `when` are mutually exclusive (a row either holds a maintained
6253
+ * list or appears/disappears as a whole — the same rule the old builder enforced).
6254
+ */
6255
+ interface MaintainedFromMetadata {
6256
+ /** Resolves the source entity whose lifecycle events maintain the view row. */
6257
+ sourceFactory: () => new (...args: unknown[]) => unknown;
6258
+ /** The lifecycle events that maintain the view row (`created`/`updated`/`removed`). */
6259
+ on: readonly MaintainEvent[];
6260
+ /** The view-row key binding (view-row key field → payload-rooted source value). */
6261
+ keyBind: Readonly<Record<string, EffectPath>>;
6262
+ /** The projection of the source payload into the view row (target attr → transform). */
6263
+ project: ProjectionMap;
6264
+ /** Bounded/ordered collection options when this declaration maintains a list. */
6265
+ collection?: {
6266
+ /** The view-row attribute that holds the maintained list (a `self.<field>`). */
6267
+ field: string;
6268
+ maxItems?: number;
6269
+ order?: 'ASC' | 'DESC';
6270
+ /** The source value the collection orders by / trims on (`$.entity.<field>`). */
6271
+ orderBy?: EffectPath;
6272
+ };
6273
+ /** Sparse-view membership predicate (mutually exclusive with `collection`). */
6274
+ when?: MembershipPredicate;
6275
+ consistency?: MaintainConsistency;
6276
+ updateMode?: MaintainUpdateMode;
6277
+ }
6445
6278
  interface KeyDefinition {
6446
6279
  /** The canonical structured key (PK/SK segment lists). */
6447
6280
  segmented: SegmentedKey;
@@ -6471,8 +6304,18 @@ interface RelationLimitOptions {
6471
6304
  * Typed as a `string` union of the known presets but kept open-ended via the
6472
6305
  * `(string & {})` tail so a future preset can be authored before this union is
6473
6306
  * widened, without a breaking change to callers.
6307
+ *
6308
+ * The union lists only the presets that are actually *reachable* as a recorded
6309
+ * `RelationOptions.pattern` / `AggregateOptions.pattern` value: `samePartition`,
6310
+ * `counter`, `embeddedSnapshot`, and the two versioned discriminators
6311
+ * `versionedLatest` / `versionedHistory` (issue #152). `materializedView` /
6312
+ * `sparseView` migrated to the model-level `@model({ kind })` selector (they are
6313
+ * a {@link ModelKind}, not a relation preset); the placeholder `edge` /
6314
+ * `dualEdge` / `versioned` / `externalProjection` names are not authored anywhere
6315
+ * and were removed. A future preset can still be written against the `(string & {})`
6316
+ * tail before it is added to this union.
6474
6317
  */
6475
- type RelationPattern = 'samePartition' | 'edge' | 'dualEdge' | 'counter' | 'embeddedSnapshot' | 'materializedView' | 'sparseView' | 'versioned' | 'externalProjection' | (string & {});
6318
+ type RelationPattern = 'samePartition' | 'counter' | 'embeddedSnapshot' | 'versionedLatest' | 'versionedHistory' | (string & {});
6476
6319
  /**
6477
6320
  * Consistency boundary a maintained write is declared against (Epic #118 §4.A.7):
6478
6321
  * `transactional` = same `TransactWriteItems`; `eventual` = asynchronous catch-up.
@@ -6549,6 +6392,23 @@ interface RelationOptions {
6549
6392
  read?: RelationReadOptions;
6550
6393
  write?: RelationWriteOptions;
6551
6394
  projection?: RelationProjection;
6395
+ /**
6396
+ * Lowered versioned-pattern declaration (issue #152, section B). Present only when
6397
+ * the relation declares `pattern: 'versionedLatest' | 'versionedHistory'` via the
6398
+ * `@hasOne/@hasMany(() => Target, (self, source) => ({...}))` callback form. The
6399
+ * declaring model is the SOURCE (a revision); the relation target is the
6400
+ * DESTINATION view row. The adapter
6401
+ * (`src/relation/maintenance-view-adapter.ts`) lowers this to the SAME `defineView`
6402
+ * snapshot IR the old `defineVersioned` produced (latest = overwrite, history =
6403
+ * append). `on` are the lifecycle events; `project` is the lowered projection map.
6404
+ */
6405
+ versioned?: {
6406
+ readonly mode: 'latest' | 'history';
6407
+ readonly on: readonly MaintainEvent[];
6408
+ readonly project: ProjectionMap;
6409
+ readonly consistency?: MaintainConsistency;
6410
+ readonly updateMode?: MaintainUpdateMode;
6411
+ };
6552
6412
  }
6553
6413
  interface RelationMetadata {
6554
6414
  type: 'hasMany' | 'hasOne' | 'belongsTo';
@@ -6646,6 +6506,30 @@ interface EntityMetadata {
6646
6506
  /** Scalar `@aggregate` fields (Epic #118 §5.2 counter / latest; issue #122). */
6647
6507
  aggregates: AggregateMetadata[];
6648
6508
  embeddedFields: EmbeddedMetadata[];
6509
+ /**
6510
+ * The model's maintenance kind (issue #152). `'entity'` (default; also assumed
6511
+ * when absent, for hand-built metadata in tests) is a plain stored entity;
6512
+ * `'materializedView'` / `'sparseView'` mark it a maintained view row fed by
6513
+ * {@link maintainedFrom}.
6514
+ */
6515
+ kind?: ModelKind;
6516
+ /**
6517
+ * Optional human-readable description of the entity (issue #154), supplied via
6518
+ * `@model({ description })`. Pure documentation metadata — it does NOT affect
6519
+ * storage, keys, or any runtime behaviour. When present it is propagated to the
6520
+ * entity entry in `manifest.json` ({@link ManifestEntity.description}) and
6521
+ * surfaces as the class docstring in the generated Python `types.py`. Absent →
6522
+ * byte-for-byte unchanged output (backward compatible).
6523
+ */
6524
+ description?: string;
6525
+ /**
6526
+ * Class-level `@maintainedFrom(...)` declarations (issue #152). Non-empty only on
6527
+ * a `materializedView` / `sparseView` model; each is one source slice the view
6528
+ * row is maintained from. The adapter lowers these to the maintenance graph's
6529
+ * `ViewDefinition` IR (replacing the old `defineView` / `ViewRegistry` path).
6530
+ * Absent / empty for a plain entity.
6531
+ */
6532
+ maintainedFrom?: MaintainedFromMetadata[];
6649
6533
  }
6650
6534
 
6651
6535
  /**
@@ -6761,4 +6645,4 @@ interface CdcEmulatorOptions {
6761
6645
  }
6762
6646
  type ShardId = string;
6763
6647
 
6764
- export { type RelationMetadata as $, type AggregateOptions as A, type BatchGetExecInput as B, type ChangeEvent as C, type DynamoDBOperation as D, type Executor as E, type FieldOptions as F, type GsiDefinition as G, type ResolvedKey as H, type Item as I, type CdcEmulatorOptions as J, type KeyDefinition as K, type ChangeHandler as L, type ModelStatic as M, type Unsubscribe as N, type FaultSpec as O, type PutInput as P, type ConcurrentRecomputeRef as Q, type ReadExecOptions as R, type SelectableOf as S, type TransactWriteExecItem as T, type UpdateInput as U, type EventLog as V, type WriteExecOptions as W, type ReplayOptions as X, type ShardId as Y, type ViewDefinition as Z, type ProjectionDefinition as _, type ExecutorResult as a, type ContractKeyFieldRef as a$, type TransactionItemSpec as a0, type MaintainEffect as a1, type Param as a2, type ParamDescriptor as a3, type DefinitionMap as a4, type OperationDefinition as a5, type WriteDefinitionOptions as a6, type PartialQueryKeyOf as a7, type StrictSelectSpec as a8, type EntityInput as a9, type ChangeBatch as aA, type ChangeEventName as aB, type ClockMode as aC, type CollectionEffect as aD, type CollectionOptions as aE, type Column as aF, type ColumnMap as aG, type CommandContractMethodSpec as aH, type CommandInputShape as aI, type CommandMethod as aJ, type CommandPlan as aK, type CommandResolutionTarget as aL, type CommandResultKind as aM, type CommandSelectShape as aN, type CompiledFragment as aO, type ComposeSpec as aP, type CondSlot as aQ, type ConditionCheckInput as aR, type Connection as aS, type ContractCallSignature as aT, type ContractCardinality as aU, type ContractCommandParams as aV, type ContractCommandResult as aW, type ContractComposeNode as aX, type ContractFromRef as aY, type ContractInputArity as aZ, type ContractItem as a_, type UniqueQueryKeyOf as aa, type EntityRef as ab, type ConditionInput as ac, type QueryModelContract as ad, type QueryMethodSpec as ae, type CommandModelContract as af, type CommandMethodSpec as ag, type ContractSpec as ah, type QuerySpec as ai, type CommandSpec as aj, type ContextSpec as ak, type OperationsDocument as al, type AnyOperationDefinition as am, type BridgeBundle as an, type ConditionSpec as ao, type AggregateMetadata as ap, type BatchDeleteRequest as aq, type BatchGetOptions as ar, type BatchGetRequest as as, BatchGetResult as at, type BatchPutRequest as au, type BatchResult as av, type BatchWriteRequest as aw, CONTRACT_RANGE_FANOUT_CONCURRENCY as ax, type CdcMode as ay, type Change as az, type WriteResult as b, type MutateParallelResult as b$, type ContractKeyInput as b0, type ContractKeyRef as b1, type ContractKeySpec as b2, type ContractKind as b3, type ContractMethodOp as b4, type ContractParamRef as b5, type ContractQueryParams as b6, type ContractResolution as b7, type CounterAggregate as b8, type CounterEffect as b9, type KeySegment as bA, type KeySlot as bB, type KeyStructure as bC, type KeyedResult as bD, LIFECYCLE_CONTRACT_MARKER as bE, type LifecycleContract as bF, type LifecycleEffects as bG, type LiteralParam as bH, type MaintainConsistency as bI, type MaintainEvent as bJ, type MaintainItem as bK, type MaintainTrigger as bL, type MaintainUpdateMode as bM, type MaintenanceGraph as bN, type ManifestEntity as bO, type ManifestField as bP, type ManifestFieldType as bQ, type ManifestGsi as bR, type ManifestKey as bS, type ManifestRelation as bT, type ManifestTable as bU, type MembershipEffect as bV, type MembershipPredicate as bW, type MembershipPredicateOp as bX, type ModelRef as bY, type MutateMode as bZ, type MutateOptions as b_, type CtxBase as ba, DEFAULT_MAX_ATTEMPTS as bb, DEFAULT_RETRY_POLICY as bc, type DeleteOptions as bd, type DeriveEffect as be, type DerivedEdgeWrite as bf, type DerivedUpdate as bg, type DescriptorBinding as bh, ENTITY_WRITES_MARKER as bi, type EdgeEffect as bj, type EffectPath as bk, type EmbeddedMetadata as bl, type EmitEffect as bm, type EntityWritesDefinition as bn, type EntityWritesShape as bo, type ExecutableCommandContract as bp, type ExecutableQueryContract as bq, type FilterInput as br, type FilterSpec as bs, type FragmentInput as bt, type GsiDefinitionMarker as bu, type GsiOptions as bv, type IdempotencyEffect as bw, type InProcessWriteDescriptor as bx, type InputArity as by, type KeyDefinitionMarker as bz, type DeleteInput as c, type UniqueEffect as c$, type MutateTransactionResult as c0, type MutationBody as c1, type MutationDescriptorMap as c2, type MutationFragment as c3, type MutationInputProxy as c4, type MutationInputRef as c5, type MutationIntent as c6, type NumberParam as c7, type OperationKind as c8, type OperationSpec as c9, type ReadRouteResult as cA, type RecordedCompose as cB, type RelationBuilder as cC, type RelationConsistency as cD, type RelationLimitOptions as cE, type RelationPattern as cF, type RelationProjection as cG, type RelationReadOptions as cH, type RelationSelect as cI, type RelationSpec as cJ, type RelationUpdateMode as cK, type RelationWriteOptions as cL, type RequiresEffect as cM, type Resolution as cN, type RetryInfo as cO, type RetryOperationKind as cP, SPEC_VERSION as cQ, type SegmentSpec as cR, type SegmentedKey as cS, type SelectBuilder as cT, type SelectOf as cU, type SnapshotEffect as cV, type StartingPosition as cW, type StreamViewType as cX, type StringParam as cY, TransactionContext as cZ, type TransactionItemType as c_, type ParallelOpResult as ca, type ParamKind as cb, type ParamSpec as cc, type ParamStructure as cd, type PersistCtx as ce, type PersistOrigin as cf, type PlannedCommandMethod as cg, type ProjectionDefinitionInput as ch, type ProjectionDefinitionMap as ci, type ProjectionMap as cj, type ProjectionTransform as ck, type ProjectionTransformOp as cl, type ProjectionVia as cm, type PutOptions as cn, type QueryContractMethodSpec as co, type QueryEnvelopeResult as cp, type QueryKeyOf as cq, type QueryMethod as cr, type QueryResult as cs, type RangeConditionSpec as ct, type ReadEnvelope as cu, type ReadOpCtx as cv, type ReadOpKind as cw, type ReadOperationType as cx, type ReadRouteDescriptor as cy, type ReadRouteOptions as cz, type BatchWriteExecItem as d, isMaintainTrigger as d$, type Updatable as d0, type UpdateOptions as d1, type VersionedDefinition as d2, type VersionedDefinitionInput as d3, type ViewDefinitionInput as d4, type ViewDefinitionMap as d5, ViewRegistry as d6, type ViewSource as d7, type ViewSourceSlice as d8, type WhenSpec as d9, defineViews as dA, entityWrites as dB, executeBatchGet as dC, executeBatchWrite as dD, executeCommandMethod as dE, executeDelete as dF, executeKeyedBatchGet as dG, executePut as dH, executeQueryMethod as dI, executeRangeFanout as dJ, executeTransaction as dK, executeUpdate as dL, from as dM, getEntityWrites as dN, gsi as dO, identity as dP, isColumn as dQ, isCommandModelContract as dR, isCommandPlan as dS, isContractComposeNode as dT, isContractFromRef as dU, isContractKeyFieldRef as dV, isContractKeyRef as dW, isContractParamRef as dX, isEntityWritesDefinition as dY, isKeySegment as dZ, isLifecycleContract as d_, type WriteCtx as da, type WriteDescriptor as db, type WriteEnvelope as dc, type WriteInput as dd, type WriteKind as de, type WriteLifecyclePhase as df, type WriteMiddleware as dg, type WriteOperationType as dh, type WriteRecorder as di, type WriteResultProjection as dj, attachModelClass as dk, buildDeleteInput as dl, buildMaintenanceGraph as dm, buildPutInput as dn, buildUpdateInput as dp, compileFragment as dq, compileMutationPlan as dr, compileSingleFragmentPlan as ds, cond as dt, contractOfMethodSpec as du, definePlan as dv, defineProjection as dw, defineProjections as dx, defineVersioned as dy, defineView as dz, type BatchExecOptions as e, isMutationFragment as e0, isMutationInputRef as e1, isParam as e2, isPlannedCommandMethod as e3, isProjectionDefinition as e4, isQueryModelContract as e5, isRetryableError as e6, isRetryableTransactionCancellation as e7, isViewDefinition as e8, k as e9, key as ea, lifecyclePhaseForIntent as eb, maintainTrigger as ec, mintContractKeyFieldRef as ed, mintContractParamRef as ee, mutation as ef, param as eg, preview as eh, publicCommandModel as ei, publicQueryModel as ej, query as ek, resolveLifecycle as el, whenMember as em, wholeKeysSentinel as en, DDBModel as f, type PrimaryKeyOf as g, type RequestContext as h, type Middleware as i, type ReadRequestKind as j, type CtxModel as k, type ReadParams as l, type ReadRequestCtx as m, type RetryPolicy as n, type ExecutionPlanSpec as o, type EntityMetadata as p, type DynamoType as q, type RelationOptions as r, type AggregateValue as s, type SelectBuilderSpec as t, type RawCondition as u, type TransactionSpec as v, type Manifest as w, type RetryOverride as x, type ExecutionPlan as y, type FieldMetadata as z };
6648
+ export { type FaultSpec as $, type AggregateOptions as A, type BatchGetExecInput as B, type ChangeEvent as C, type DynamoDBOperation as D, type Executor as E, type FieldOptions as F, type GsiDefinition as G, type SelectBuilderSpec as H, type Item as I, type RawCondition as J, type KeyDefinition as K, type TransactionSpec as L, type ModelStatic as M, type Manifest as N, type RetryOverride as O, type PutInput as P, type ExecutionPlan as Q, type ReadExecOptions as R, type SelectableOf as S, type TransactWriteExecItem as T, type UpdateInput as U, type FieldMetadata as V, type WriteExecOptions as W, type ResolvedKey as X, type CdcEmulatorOptions as Y, type ChangeHandler as Z, type Unsubscribe as _, type ExecutorResult as a, type ContractCardinality as a$, type ConcurrentRecomputeRef as a0, type EventLog as a1, type ReplayOptions as a2, type ShardId as a3, type ViewDefinition as a4, type RelationMetadata as a5, type TransactionItemSpec as a6, type MaintainEffect as a7, type Param as a8, type ParamDescriptor as a9, BatchGetResult as aA, type BatchPutRequest as aB, type BatchResult as aC, type BatchWriteRequest as aD, CONTRACT_RANGE_FANOUT_CONCURRENCY as aE, type CdcMode as aF, type Change as aG, type ChangeBatch as aH, type ChangeEventName as aI, type ClockMode as aJ, type CollectionEffect as aK, type CollectionOptions as aL, type Column as aM, type ColumnMap as aN, type CommandContractMethodSpec as aO, type CommandInputShape as aP, type CommandMethod as aQ, type CommandPlan as aR, type CommandResolutionTarget as aS, type CommandResultKind as aT, type CommandSelectShape as aU, type CompiledFragment as aV, type ComposeSpec as aW, type CondSlot as aX, type ConditionCheckInput as aY, type Connection as aZ, type ContractCallSignature as a_, type DefinitionMap as aa, type OperationDefinition as ab, type WriteDefinitionOptions as ac, type PartialQueryKeyOf as ad, type StrictSelectSpec as ae, type ReadDefinitionOptions as af, type EntityInput as ag, type UniqueQueryKeyOf as ah, type EntityRef as ai, type ConditionInput as aj, type QueryModelContract as ak, type QueryMethodSpec as al, type CommandModelContract as am, type CommandMethodSpec as an, type ContractSpec as ao, type QuerySpec as ap, type CommandSpec as aq, type ContextSpec as ar, type OperationsDocument as as, type AnyOperationDefinition as at, type BridgeBundle as au, type ConditionSpec as av, type AggregateMetadata as aw, type BatchDeleteRequest as ax, type BatchGetOptions as ay, type BatchGetRequest as az, type WriteResult as b, type MutateMode as b$, type ContractCommandParams as b0, type ContractCommandResult as b1, type ContractComposeNode as b2, type ContractFromRef as b3, type ContractInputArity as b4, type ContractItem as b5, type ContractKeyFieldRef as b6, type ContractKeyInput as b7, type ContractKeyRef as b8, type ContractKeySpec as b9, type FragmentInput as bA, type GsiDefinitionMarker as bB, type GsiOptions as bC, type IdempotencyEffect as bD, type InProcessWriteDescriptor as bE, type InputArity as bF, type KeyDefinitionMarker as bG, type KeySegment as bH, type KeySlot as bI, type KeyStructure as bJ, type KeyedResult as bK, LIFECYCLE_CONTRACT_MARKER as bL, type LifecycleContract as bM, type LifecycleEffects as bN, type LiteralParam as bO, type MaintainItem as bP, type MaintainTrigger as bQ, type MaintenanceGraph as bR, type ManifestEntity as bS, type ManifestField as bT, type ManifestFieldType as bU, type ManifestGsi as bV, type ManifestKey as bW, type ManifestRelation as bX, type ManifestTable as bY, type MembershipEffect as bZ, type ModelRef as b_, type ContractKind as ba, type ContractMethodOp as bb, type ContractParamRef as bc, type ContractQueryParams as bd, type ContractResolution as be, type CounterAggregate as bf, type CounterEffect as bg, type CtxBase as bh, DEFAULT_MAX_ATTEMPTS as bi, DEFAULT_RETRY_POLICY as bj, type DeleteOptions as bk, type DeriveEffect as bl, type DerivedEdgeWrite as bm, type DerivedUpdate as bn, type DescriptorBinding as bo, ENTITY_WRITES_MARKER as bp, type EdgeEffect as bq, type EffectPath as br, type EmbeddedMetadata as bs, type EmitEffect as bt, type EntityWritesDefinition as bu, type EntityWritesShape as bv, type ExecutableCommandContract as bw, type ExecutableQueryContract as bx, type FilterInput as by, type FilterSpec as bz, type DeleteInput as c, type UpdateOptions as c$, type MutateOptions as c0, type MutateParallelResult as c1, type MutateTransactionResult as c2, type MutationBody as c3, type MutationDescriptorMap as c4, type MutationFragment as c5, type MutationInputProxy as c6, type MutationInputRef as c7, type MutationIntent as c8, type NumberParam as c9, type RelationBuilder as cA, type RelationConsistency as cB, type RelationLimitOptions as cC, type RelationPattern as cD, type RelationProjection as cE, type RelationReadOptions as cF, type RelationSelect as cG, type RelationSpec as cH, type RelationUpdateMode as cI, type RelationWriteOptions as cJ, type RequiresEffect as cK, type Resolution as cL, type RetryInfo as cM, type RetryOperationKind as cN, SPEC_VERSION as cO, type SegmentSpec as cP, type SegmentedKey as cQ, type SelectBuilder as cR, type SelectOf as cS, type SnapshotEffect as cT, type StartingPosition as cU, type StreamViewType as cV, type StringParam as cW, TransactionContext as cX, type TransactionItemType as cY, type UniqueEffect as cZ, type Updatable as c_, type OperationKind as ca, type OperationSpec as cb, type ParallelOpResult as cc, type ParamKind as cd, type ParamSpec as ce, type ParamStructure as cf, type PersistCtx as cg, type PersistOrigin as ch, type PlannedCommandMethod as ci, type ProjectionMap as cj, type ProjectionTransformOp as ck, type PutOptions as cl, type QueryContractMethodSpec as cm, type QueryEnvelopeResult as cn, type QueryKeyOf as co, type QueryMethod as cp, type QueryResult as cq, type RangeConditionSpec as cr, type ReadEnvelope as cs, type ReadOpCtx as ct, type ReadOpKind as cu, type ReadOperationType as cv, type ReadRouteDescriptor as cw, type ReadRouteOptions as cx, type ReadRouteResult as cy, type RecordedCompose as cz, type BatchWriteExecItem as d, mintContractKeyFieldRef as d$, type ViewSourceSlice as d0, type WhenSpec as d1, type WriteCtx as d2, type WriteDescriptor as d3, type WriteEnvelope as d4, type WriteInput as d5, type WriteKind as d6, type WriteLifecyclePhase as d7, type WriteMiddleware as d8, type WriteOperationType as d9, from as dA, getEntityWrites as dB, gsi as dC, identity as dD, isColumn as dE, isCommandModelContract as dF, isCommandPlan as dG, isContractComposeNode as dH, isContractFromRef as dI, isContractKeyFieldRef as dJ, isContractKeyRef as dK, isContractParamRef as dL, isEntityWritesDefinition as dM, isKeySegment as dN, isLifecycleContract as dO, isMaintainTrigger as dP, isMutationFragment as dQ, isMutationInputRef as dR, isParam as dS, isPlannedCommandMethod as dT, isQueryModelContract as dU, isRetryableError as dV, isRetryableTransactionCancellation as dW, k as dX, key as dY, lifecyclePhaseForIntent as dZ, maintainTrigger as d_, type WriteRecorder as da, type WriteResultProjection as db, attachModelClass as dc, buildDeleteInput as dd, buildMaintenanceGraph as de, buildPutInput as df, buildUpdateInput as dg, collectViewDefinitions as dh, compileFragment as di, compileMutationPlan as dj, compileSingleFragmentPlan as dk, cond as dl, contractOfMethodSpec as dm, definePlan as dn, entityWrites as dp, executeBatchGet as dq, executeBatchWrite as dr, executeCommandMethod as ds, executeDelete as dt, executeKeyedBatchGet as du, executePut as dv, executeQueryMethod as dw, executeRangeFanout as dx, executeTransaction as dy, executeUpdate as dz, type BatchExecOptions as e, mintContractParamRef as e0, mutation as e1, param as e2, preview as e3, publicCommandModel as e4, publicQueryModel as e5, query as e6, resolveLifecycle as e7, wholeKeysSentinel as e8, DDBModel as f, type PrimaryKeyOf as g, type RequestContext as h, type Middleware as i, type ReadRequestKind as j, type CtxModel as k, type ReadParams as l, type ReadRequestCtx as m, type RetryPolicy as n, type ExecutionPlanSpec as o, type EntityMetadata as p, type ModelKind as q, type DynamoType as r, type ProjectionTransform as s, type MaintainEvent as t, type MembershipPredicate as u, type MaintainConsistency as v, type MaintainUpdateMode as w, type MembershipPredicateOp as x, type RelationOptions as y, type AggregateValue as z };