@openvtc/trust-tasks 0.12.1 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/index.d.ts +7 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +7 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/vta/_shared/0.1/app-state-record.d.ts +17 -0
  6. package/dist/vta/_shared/0.1/app-state-record.d.ts.map +1 -0
  7. package/dist/vta/_shared/0.1/app-state-record.js +6 -0
  8. package/dist/vta/_shared/0.1/app-state-record.js.map +1 -0
  9. package/dist/vta/app-state/delete/1.0/payload.d.ts +488 -0
  10. package/dist/vta/app-state/delete/1.0/payload.d.ts.map +1 -0
  11. package/dist/vta/app-state/delete/1.0/payload.js +248 -0
  12. package/dist/vta/app-state/delete/1.0/payload.js.map +1 -0
  13. package/dist/vta/app-state/get/1.0/payload.d.ts +611 -0
  14. package/dist/vta/app-state/get/1.0/payload.d.ts.map +1 -0
  15. package/dist/vta/app-state/get/1.0/payload.js +306 -0
  16. package/dist/vta/app-state/get/1.0/payload.js.map +1 -0
  17. package/dist/vta/app-state/get-many/1.0/payload.d.ts +716 -0
  18. package/dist/vta/app-state/get-many/1.0/payload.d.ts.map +1 -0
  19. package/dist/vta/app-state/get-many/1.0/payload.js +350 -0
  20. package/dist/vta/app-state/get-many/1.0/payload.js.map +1 -0
  21. package/dist/vta/app-state/list/1.0/payload.d.ts +778 -0
  22. package/dist/vta/app-state/list/1.0/payload.d.ts.map +1 -0
  23. package/dist/vta/app-state/list/1.0/payload.js +368 -0
  24. package/dist/vta/app-state/list/1.0/payload.js.map +1 -0
  25. package/dist/vta/app-state/put/1.0/payload.d.ts +560 -0
  26. package/dist/vta/app-state/put/1.0/payload.d.ts.map +1 -0
  27. package/dist/vta/app-state/put/1.0/payload.js +291 -0
  28. package/dist/vta/app-state/put/1.0/payload.js.map +1 -0
  29. package/dist/vta/app-state/put-many/1.0/payload.d.ts +856 -0
  30. package/dist/vta/app-state/put-many/1.0/payload.d.ts.map +1 -0
  31. package/dist/vta/app-state/put-many/1.0/payload.js +455 -0
  32. package/dist/vta/app-state/put-many/1.0/payload.js.map +1 -0
  33. package/package.json +1 -1
  34. package/src/index.ts +7 -0
  35. package/src/vta/_shared/0.1/app-state-record.ts +17 -0
  36. package/src/vta/app-state/delete/1.0/payload.ts +323 -0
  37. package/src/vta/app-state/get/1.0/payload.ts +404 -0
  38. package/src/vta/app-state/get-many/1.0/payload.ts +469 -0
  39. package/src/vta/app-state/list/1.0/payload.ts +509 -0
  40. package/src/vta/app-state/put/1.0/payload.ts +382 -0
  41. package/src/vta/app-state/put-many/1.0/payload.ts +584 -0
@@ -0,0 +1,584 @@
1
+ /**
2
+ * Generated by scripts/build-ts-bindings.mjs — DO NOT EDIT BY HAND.
3
+ * Source: specs/vta/app-state/put-many/1.0/payload.schema.json
4
+ */
5
+
6
+ /**
7
+ * One namespace per batch. Atomicity is only meaningful within the counter the writes take their versions from, and that counter is per (contextId, namespace).
8
+ */
9
+ export type Namespace = string;
10
+ /**
11
+ * One write within the batch. Shaped exactly like a vta/app-state/put payload minus the context and namespace, which the batch supplies.
12
+ */
13
+ export type Write =
14
+ | {
15
+ [k: string]: unknown | undefined;
16
+ }
17
+ | {
18
+ [k: string]: unknown | undefined;
19
+ };
20
+ /**
21
+ * Application-chosen identifier for a record within a namespace. Opaque to the maintainer: it MUST NOT be parsed, normalized, or case-folded, and prefix matching in `list` is a byte-prefix comparison over the UTF-8 encoding. Applications SHOULD use `/`-delimited hierarchical keys (`community/acme`, `contact/z6Mk…`) so that `prefix` can address a record family, but the delimiter is a convention between an application and itself — the maintainer attaches no meaning to it.
22
+ */
23
+ export type Key = string;
24
+ /**
25
+ * The new version, on `written`.
26
+ */
27
+ export type Version = number;
28
+ /**
29
+ * On `conflict`: the version the maintainer actually holds. Absent when the conflict is that no record exists (`expectedVersion` was positive and the address is empty).
30
+ */
31
+ export type Version1 = number;
32
+ /**
33
+ * The namespace's counter value after the batch. A writer that is also a sync consumer can adopt this instead of issuing a list call to discover where its own writes landed.
34
+ */
35
+ export type Version2 = number;
36
+
37
+ /**
38
+ * Write up to 64 application-state records in one round trip, each carrying its own optimistic-concurrency precondition. The batch `mode` decides what a single failure costs: `independent` (the default) applies each write on its own merits, `atomic` applies all or none.
39
+ */
40
+ export interface VTAApplicationStatePutManyPayload {
41
+ /**
42
+ * The VTA context the records are scoped to; the isolation boundary.
43
+ */
44
+ contextId: string;
45
+ namespace: Namespace;
46
+ /**
47
+ * `independent` applies each write on its own merits, so one conflicted record does not block the other nine — what a flush of unrelated edits wants, and why it is the default. `atomic` applies all or none, for records carrying a joint invariant. An atomic DEFAULT would let one stale record silently wedge an entire flush, and a caller could not tell a wedged flush from a slow one.
48
+ */
49
+ mode?: "independent" | "atomic";
50
+ /**
51
+ * The writes to apply. Keys MUST be distinct: two writes to one key in a batch have no defined order and are refused rather than serialised.
52
+ *
53
+ * @minItems 1
54
+ * @maxItems 64
55
+ */
56
+ writes: [Write, ...Write[]];
57
+ ext?: Ext;
58
+ }
59
+ /**
60
+ * Ecosystem-defined extension members per SPEC.md §4.5.1.
61
+ */
62
+ export interface Ext {
63
+ [k: string]: unknown | undefined;
64
+ }
65
+ /**
66
+ * Success response to vta/app-state/put-many in `independent` mode. Type https://trusttasks.org/spec/vta/app-state/put-many/1.0#response. A response is returned even when some writes conflicted, because the task did what it promised — applied each write on its own merits — and the per-record outcomes are the answer rather than the failure. An `atomic` batch that does not apply is a trust-task-error carrying vta/app-state/put-many:atomicBatchRejected, whose details carry the same per-record outcomes.
67
+ */
68
+ export interface VTAApplicationStatePutManyResponsePayload {
69
+ /**
70
+ * The mode the maintainer applied, echoed so a caller relying on the default sees what it got.
71
+ */
72
+ mode: "independent" | "atomic";
73
+ /**
74
+ * One result per requested write, in request order. Every write is accounted for.
75
+ *
76
+ * @minItems 1
77
+ * @maxItems 64
78
+ */
79
+ results: [WriteResult, ...WriteResult[]];
80
+ highWatermark?: Version2;
81
+ ext?: Ext1;
82
+ }
83
+ /**
84
+ * The outcome of one write within a `vta/app-state/put-many` batch. Per-record rather than per-batch, because the default batch mode applies each write on its own merits: a caller flushing ten unrelated edits needs to know which one conflicted, not merely that something did.
85
+ */
86
+ export interface WriteResult {
87
+ key: Key;
88
+ /**
89
+ * `written`: applied, and `version` carries the new value. `conflict`: `expectedVersion` did not match; `currentVersion`, `currentValue` and `currentDeleted` carry the maintainer's view so the caller can resolve without a re-read. `tooLarge`: the value exceeded the per-record cap; `limitBytes` and `actualBytes` say by how much. `notFound`: a `mergePatch` write named an address with no live record. `skipped`: atomic mode only — this write was not attempted because another in the batch failed.
90
+ */
91
+ outcome: "written" | "conflict" | "tooLarge" | "notFound" | "skipped";
92
+ version?: Version;
93
+ /**
94
+ * On `written`: true when no live record existed at the address beforehand.
95
+ */
96
+ created?: boolean;
97
+ currentVersion?: Version1;
98
+ /**
99
+ * On `conflict`: the value the maintainer actually holds, returned WITH the rejection rather than left for the caller to re-read. A bare rejection has no fixed point under contention — between the rejection and the re-read the record can change again — so returning the winner's view removes the race rather than narrowing it. Absent when `currentDeleted` is true or no record exists.
100
+ */
101
+ currentValue?: {
102
+ [k: string]: unknown | undefined;
103
+ };
104
+ /**
105
+ * On `conflict`: true when the address holds a tombstone rather than a live record.
106
+ */
107
+ currentDeleted?: boolean;
108
+ /**
109
+ * On `tooLarge`: the maintainer's per-record cap in bytes.
110
+ */
111
+ limitBytes?: number;
112
+ /**
113
+ * On `tooLarge`: the size of the rejected value in bytes.
114
+ */
115
+ actualBytes?: number;
116
+ }
117
+ /**
118
+ * Ecosystem-defined extension members per SPEC.md §4.5.1.
119
+ */
120
+ export interface Ext1 {
121
+ [k: string]: unknown | undefined;
122
+ }
123
+
124
+ /** Trust Task type URI. */
125
+ export const TYPE_URI = "https://trusttasks.org/spec/vta/app-state/put-many/1.0" as const;
126
+
127
+ /** Stable alias for this specification's request payload shape. */
128
+ export type Payload = VTAApplicationStatePutManyPayload;
129
+
130
+ /** Trust Task response type URI (request type URI + "#response"). */
131
+ export const RESPONSE_TYPE_URI = "https://trusttasks.org/spec/vta/app-state/put-many/1.0#response" as const;
132
+
133
+ /** Stable alias for this specification's success-response payload shape. */
134
+ export type Response = VTAApplicationStatePutManyResponsePayload;
135
+
136
+ /**
137
+ * This specification's payload schema, as a value.
138
+ *
139
+ * SPEC.md §7.2 item 2 is performed against this. It is shipped as data
140
+ * rather than only as a `.json` file because TypeScript types are erased
141
+ * at runtime: without a schema a consumer has nothing to validate, and
142
+ * every REQUIRED payload member is optional in practice. Cross-file
143
+ * `$ref`s are already inlined, so it needs no resolver.
144
+ */
145
+ export const PAYLOAD_SCHEMA = {
146
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
147
+ "$id": "https://trusttasks.org/spec/vta/app-state/put-many/1.0",
148
+ "title": "VTA Application State Put-Many — payload",
149
+ "description": "Write up to 64 application-state records in one round trip, each carrying its own optimistic-concurrency precondition. The batch `mode` decides what a single failure costs: `independent` (the default) applies each write on its own merits, `atomic` applies all or none.",
150
+ "type": "object",
151
+ "additionalProperties": false,
152
+ "required": [
153
+ "contextId",
154
+ "namespace",
155
+ "writes"
156
+ ],
157
+ "properties": {
158
+ "contextId": {
159
+ "type": "string",
160
+ "minLength": 1,
161
+ "description": "The VTA context the records are scoped to; the isolation boundary."
162
+ },
163
+ "namespace": {
164
+ "$ref": "#/$defs/Namespace",
165
+ "description": "One namespace per batch. Atomicity is only meaningful within the counter the writes take their versions from, and that counter is per (contextId, namespace)."
166
+ },
167
+ "mode": {
168
+ "type": "string",
169
+ "enum": [
170
+ "independent",
171
+ "atomic"
172
+ ],
173
+ "default": "independent",
174
+ "description": "`independent` applies each write on its own merits, so one conflicted record does not block the other nine — what a flush of unrelated edits wants, and why it is the default. `atomic` applies all or none, for records carrying a joint invariant. An atomic DEFAULT would let one stale record silently wedge an entire flush, and a caller could not tell a wedged flush from a slow one.",
175
+ "$comment": "The default is load-bearing rather than a convenience; see the spec's Abstract."
176
+ },
177
+ "writes": {
178
+ "type": "array",
179
+ "minItems": 1,
180
+ "maxItems": 64,
181
+ "items": {
182
+ "$ref": "#/$defs/Write"
183
+ },
184
+ "description": "The writes to apply. Keys MUST be distinct: two writes to one key in a batch have no defined order and are refused rather than serialised."
185
+ },
186
+ "ext": {
187
+ "$ref": "#/$defs/Ext",
188
+ "description": "Ecosystem-defined extension members per SPEC.md §4.5.1."
189
+ }
190
+ },
191
+ "$defs": {
192
+ "Write": {
193
+ "title": "Write",
194
+ "description": "One write within the batch. Shaped exactly like a vta/app-state/put payload minus the context and namespace, which the batch supplies.",
195
+ "type": "object",
196
+ "additionalProperties": false,
197
+ "required": [
198
+ "key"
199
+ ],
200
+ "oneOf": [
201
+ {
202
+ "required": [
203
+ "value"
204
+ ],
205
+ "not": {
206
+ "required": [
207
+ "mergePatch"
208
+ ]
209
+ }
210
+ },
211
+ {
212
+ "required": [
213
+ "mergePatch"
214
+ ],
215
+ "not": {
216
+ "required": [
217
+ "value"
218
+ ]
219
+ }
220
+ }
221
+ ],
222
+ "properties": {
223
+ "key": {
224
+ "$ref": "#/$defs/Key"
225
+ },
226
+ "value": {
227
+ "description": "The complete new value, replacing whatever the record held. Any JSON value, including `null`. Mutually exclusive with `mergePatch`."
228
+ },
229
+ "mergePatch": {
230
+ "type": "object",
231
+ "description": "An RFC 7386 JSON Merge Patch applied to the record's current value. Requires a live record at the address; otherwise this write's outcome is `notFound`. Mutually exclusive with `value`."
232
+ },
233
+ "expectedVersion": {
234
+ "$ref": "#/$defs/ExpectedVersion",
235
+ "description": "This write's own precondition, evaluated independently of every other write in the batch. A positive value requires the record to be at exactly that version; 0 requires that no live record exists."
236
+ }
237
+ }
238
+ },
239
+ "Response": {
240
+ "$anchor": "response",
241
+ "title": "VTA Application State Put-Many — response payload",
242
+ "description": "Success response to vta/app-state/put-many in `independent` mode. Type https://trusttasks.org/spec/vta/app-state/put-many/1.0#response. A response is returned even when some writes conflicted, because the task did what it promised — applied each write on its own merits — and the per-record outcomes are the answer rather than the failure. An `atomic` batch that does not apply is a trust-task-error carrying vta/app-state/put-many:atomicBatchRejected, whose details carry the same per-record outcomes.",
243
+ "type": "object",
244
+ "additionalProperties": false,
245
+ "required": [
246
+ "mode",
247
+ "results"
248
+ ],
249
+ "properties": {
250
+ "mode": {
251
+ "type": "string",
252
+ "enum": [
253
+ "independent",
254
+ "atomic"
255
+ ],
256
+ "description": "The mode the maintainer applied, echoed so a caller relying on the default sees what it got."
257
+ },
258
+ "results": {
259
+ "type": "array",
260
+ "minItems": 1,
261
+ "maxItems": 64,
262
+ "items": {
263
+ "$ref": "#/$defs/WriteResult"
264
+ },
265
+ "description": "One result per requested write, in request order. Every write is accounted for."
266
+ },
267
+ "highWatermark": {
268
+ "$ref": "#/$defs/Version",
269
+ "description": "The namespace's counter value after the batch. A writer that is also a sync consumer can adopt this instead of issuing a list call to discover where its own writes landed."
270
+ },
271
+ "ext": {
272
+ "$ref": "#/$defs/Ext",
273
+ "description": "Ecosystem-defined extension members per SPEC.md §4.5.1."
274
+ }
275
+ }
276
+ },
277
+ "Ext": {
278
+ "title": "Ext",
279
+ "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
280
+ "type": "object",
281
+ "minProperties": 1,
282
+ "additionalProperties": true,
283
+ "propertyNames": {
284
+ "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
285
+ }
286
+ },
287
+ "Version": {
288
+ "title": "Version",
289
+ "description": "A value of the namespace's monotonic write counter (see this schema's description). Server-assigned; a producer never chooses one.",
290
+ "type": "integer",
291
+ "minimum": 1
292
+ },
293
+ "WriteResult": {
294
+ "title": "WriteResult",
295
+ "description": "The outcome of one write within a `vta/app-state/put-many` batch. Per-record rather than per-batch, because the default batch mode applies each write on its own merits: a caller flushing ten unrelated edits needs to know which one conflicted, not merely that something did.",
296
+ "type": "object",
297
+ "additionalProperties": false,
298
+ "required": [
299
+ "key",
300
+ "outcome"
301
+ ],
302
+ "properties": {
303
+ "key": {
304
+ "$ref": "#/$defs/Key"
305
+ },
306
+ "outcome": {
307
+ "type": "string",
308
+ "enum": [
309
+ "written",
310
+ "conflict",
311
+ "tooLarge",
312
+ "notFound",
313
+ "skipped"
314
+ ],
315
+ "description": "`written`: applied, and `version` carries the new value. `conflict`: `expectedVersion` did not match; `currentVersion`, `currentValue` and `currentDeleted` carry the maintainer's view so the caller can resolve without a re-read. `tooLarge`: the value exceeded the per-record cap; `limitBytes` and `actualBytes` say by how much. `notFound`: a `mergePatch` write named an address with no live record. `skipped`: atomic mode only — this write was not attempted because another in the batch failed."
316
+ },
317
+ "version": {
318
+ "$ref": "#/$defs/Version",
319
+ "description": "The new version, on `written`."
320
+ },
321
+ "created": {
322
+ "type": "boolean",
323
+ "description": "On `written`: true when no live record existed at the address beforehand."
324
+ },
325
+ "currentVersion": {
326
+ "$ref": "#/$defs/Version",
327
+ "description": "On `conflict`: the version the maintainer actually holds. Absent when the conflict is that no record exists (`expectedVersion` was positive and the address is empty)."
328
+ },
329
+ "currentValue": {
330
+ "description": "On `conflict`: the value the maintainer actually holds, returned WITH the rejection rather than left for the caller to re-read. A bare rejection has no fixed point under contention — between the rejection and the re-read the record can change again — so returning the winner's view removes the race rather than narrowing it. Absent when `currentDeleted` is true or no record exists."
331
+ },
332
+ "currentDeleted": {
333
+ "type": "boolean",
334
+ "description": "On `conflict`: true when the address holds a tombstone rather than a live record."
335
+ },
336
+ "limitBytes": {
337
+ "type": "integer",
338
+ "minimum": 0,
339
+ "description": "On `tooLarge`: the maintainer's per-record cap in bytes."
340
+ },
341
+ "actualBytes": {
342
+ "type": "integer",
343
+ "minimum": 0,
344
+ "description": "On `tooLarge`: the size of the rejected value in bytes."
345
+ }
346
+ }
347
+ },
348
+ "Key": {
349
+ "title": "Key",
350
+ "description": "Application-chosen identifier for a record within a namespace. Opaque to the maintainer: it MUST NOT be parsed, normalized, or case-folded, and prefix matching in `list` is a byte-prefix comparison over the UTF-8 encoding. Applications SHOULD use `/`-delimited hierarchical keys (`community/acme`, `contact/z6Mk…`) so that `prefix` can address a record family, but the delimiter is a convention between an application and itself — the maintainer attaches no meaning to it.",
351
+ "type": "string",
352
+ "minLength": 1,
353
+ "maxLength": 512,
354
+ "pattern": "^[^\\u0000]+$"
355
+ },
356
+ "ExpectedVersion": {
357
+ "title": "ExpectedVersion",
358
+ "description": "Optimistic-concurrency precondition on a write. A positive value requires that the record's current `version` equals it exactly. Zero means \"create only\" — the write applies only if no LIVE record exists at the address, which is what makes lease acquisition safe: without it two instances can each read \"absent\", each write, and each believe it won. A tombstone is not a live record, so `expectedVersion: 0` succeeds over one; the created record takes the namespace's next counter value, which is necessarily greater than the tombstone's.",
359
+ "type": "integer",
360
+ "minimum": 0
361
+ },
362
+ "Namespace": {
363
+ "title": "Namespace",
364
+ "description": "Scopes one application's records within a context, so several tools can share a context without colliding — `openvtc`, `cnm`, an agent runtime. The maintainer MUST NOT interpret the value; it is an opaque partition name. Namespaces are first-come and unreserved, so an application SHOULD pick a stable, specific one: a future per-namespace ACL would grant on this exact string, which makes renaming a namespace a migration rather than an edit.",
365
+ "type": "string",
366
+ "minLength": 1,
367
+ "maxLength": 64,
368
+ "pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
369
+ }
370
+ }
371
+ } as const;
372
+
373
+ /** As {@link PAYLOAD_SCHEMA}, for the success-response variant. */
374
+ export const RESPONSE_PAYLOAD_SCHEMA = {
375
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
376
+ "$ref": "#/$defs/Response",
377
+ "$defs": {
378
+ "Write": {
379
+ "title": "Write",
380
+ "description": "One write within the batch. Shaped exactly like a vta/app-state/put payload minus the context and namespace, which the batch supplies.",
381
+ "type": "object",
382
+ "additionalProperties": false,
383
+ "required": [
384
+ "key"
385
+ ],
386
+ "oneOf": [
387
+ {
388
+ "required": [
389
+ "value"
390
+ ],
391
+ "not": {
392
+ "required": [
393
+ "mergePatch"
394
+ ]
395
+ }
396
+ },
397
+ {
398
+ "required": [
399
+ "mergePatch"
400
+ ],
401
+ "not": {
402
+ "required": [
403
+ "value"
404
+ ]
405
+ }
406
+ }
407
+ ],
408
+ "properties": {
409
+ "key": {
410
+ "$ref": "#/$defs/Key"
411
+ },
412
+ "value": {
413
+ "description": "The complete new value, replacing whatever the record held. Any JSON value, including `null`. Mutually exclusive with `mergePatch`."
414
+ },
415
+ "mergePatch": {
416
+ "type": "object",
417
+ "description": "An RFC 7386 JSON Merge Patch applied to the record's current value. Requires a live record at the address; otherwise this write's outcome is `notFound`. Mutually exclusive with `value`."
418
+ },
419
+ "expectedVersion": {
420
+ "$ref": "#/$defs/ExpectedVersion",
421
+ "description": "This write's own precondition, evaluated independently of every other write in the batch. A positive value requires the record to be at exactly that version; 0 requires that no live record exists."
422
+ }
423
+ }
424
+ },
425
+ "Response": {
426
+ "$anchor": "response",
427
+ "title": "VTA Application State Put-Many — response payload",
428
+ "description": "Success response to vta/app-state/put-many in `independent` mode. Type https://trusttasks.org/spec/vta/app-state/put-many/1.0#response. A response is returned even when some writes conflicted, because the task did what it promised — applied each write on its own merits — and the per-record outcomes are the answer rather than the failure. An `atomic` batch that does not apply is a trust-task-error carrying vta/app-state/put-many:atomicBatchRejected, whose details carry the same per-record outcomes.",
429
+ "type": "object",
430
+ "additionalProperties": false,
431
+ "required": [
432
+ "mode",
433
+ "results"
434
+ ],
435
+ "properties": {
436
+ "mode": {
437
+ "type": "string",
438
+ "enum": [
439
+ "independent",
440
+ "atomic"
441
+ ],
442
+ "description": "The mode the maintainer applied, echoed so a caller relying on the default sees what it got."
443
+ },
444
+ "results": {
445
+ "type": "array",
446
+ "minItems": 1,
447
+ "maxItems": 64,
448
+ "items": {
449
+ "$ref": "#/$defs/WriteResult"
450
+ },
451
+ "description": "One result per requested write, in request order. Every write is accounted for."
452
+ },
453
+ "highWatermark": {
454
+ "$ref": "#/$defs/Version",
455
+ "description": "The namespace's counter value after the batch. A writer that is also a sync consumer can adopt this instead of issuing a list call to discover where its own writes landed."
456
+ },
457
+ "ext": {
458
+ "$ref": "#/$defs/Ext",
459
+ "description": "Ecosystem-defined extension members per SPEC.md §4.5.1."
460
+ }
461
+ }
462
+ },
463
+ "Ext": {
464
+ "title": "Ext",
465
+ "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
466
+ "type": "object",
467
+ "minProperties": 1,
468
+ "additionalProperties": true,
469
+ "propertyNames": {
470
+ "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
471
+ }
472
+ },
473
+ "Version": {
474
+ "title": "Version",
475
+ "description": "A value of the namespace's monotonic write counter (see this schema's description). Server-assigned; a producer never chooses one.",
476
+ "type": "integer",
477
+ "minimum": 1
478
+ },
479
+ "WriteResult": {
480
+ "title": "WriteResult",
481
+ "description": "The outcome of one write within a `vta/app-state/put-many` batch. Per-record rather than per-batch, because the default batch mode applies each write on its own merits: a caller flushing ten unrelated edits needs to know which one conflicted, not merely that something did.",
482
+ "type": "object",
483
+ "additionalProperties": false,
484
+ "required": [
485
+ "key",
486
+ "outcome"
487
+ ],
488
+ "properties": {
489
+ "key": {
490
+ "$ref": "#/$defs/Key"
491
+ },
492
+ "outcome": {
493
+ "type": "string",
494
+ "enum": [
495
+ "written",
496
+ "conflict",
497
+ "tooLarge",
498
+ "notFound",
499
+ "skipped"
500
+ ],
501
+ "description": "`written`: applied, and `version` carries the new value. `conflict`: `expectedVersion` did not match; `currentVersion`, `currentValue` and `currentDeleted` carry the maintainer's view so the caller can resolve without a re-read. `tooLarge`: the value exceeded the per-record cap; `limitBytes` and `actualBytes` say by how much. `notFound`: a `mergePatch` write named an address with no live record. `skipped`: atomic mode only — this write was not attempted because another in the batch failed."
502
+ },
503
+ "version": {
504
+ "$ref": "#/$defs/Version",
505
+ "description": "The new version, on `written`."
506
+ },
507
+ "created": {
508
+ "type": "boolean",
509
+ "description": "On `written`: true when no live record existed at the address beforehand."
510
+ },
511
+ "currentVersion": {
512
+ "$ref": "#/$defs/Version",
513
+ "description": "On `conflict`: the version the maintainer actually holds. Absent when the conflict is that no record exists (`expectedVersion` was positive and the address is empty)."
514
+ },
515
+ "currentValue": {
516
+ "description": "On `conflict`: the value the maintainer actually holds, returned WITH the rejection rather than left for the caller to re-read. A bare rejection has no fixed point under contention — between the rejection and the re-read the record can change again — so returning the winner's view removes the race rather than narrowing it. Absent when `currentDeleted` is true or no record exists."
517
+ },
518
+ "currentDeleted": {
519
+ "type": "boolean",
520
+ "description": "On `conflict`: true when the address holds a tombstone rather than a live record."
521
+ },
522
+ "limitBytes": {
523
+ "type": "integer",
524
+ "minimum": 0,
525
+ "description": "On `tooLarge`: the maintainer's per-record cap in bytes."
526
+ },
527
+ "actualBytes": {
528
+ "type": "integer",
529
+ "minimum": 0,
530
+ "description": "On `tooLarge`: the size of the rejected value in bytes."
531
+ }
532
+ }
533
+ },
534
+ "Key": {
535
+ "title": "Key",
536
+ "description": "Application-chosen identifier for a record within a namespace. Opaque to the maintainer: it MUST NOT be parsed, normalized, or case-folded, and prefix matching in `list` is a byte-prefix comparison over the UTF-8 encoding. Applications SHOULD use `/`-delimited hierarchical keys (`community/acme`, `contact/z6Mk…`) so that `prefix` can address a record family, but the delimiter is a convention between an application and itself — the maintainer attaches no meaning to it.",
537
+ "type": "string",
538
+ "minLength": 1,
539
+ "maxLength": 512,
540
+ "pattern": "^[^\\u0000]+$"
541
+ },
542
+ "ExpectedVersion": {
543
+ "title": "ExpectedVersion",
544
+ "description": "Optimistic-concurrency precondition on a write. A positive value requires that the record's current `version` equals it exactly. Zero means \"create only\" — the write applies only if no LIVE record exists at the address, which is what makes lease acquisition safe: without it two instances can each read \"absent\", each write, and each believe it won. A tombstone is not a live record, so `expectedVersion: 0` succeeds over one; the created record takes the namespace's next counter value, which is necessarily greater than the tombstone's.",
545
+ "type": "integer",
546
+ "minimum": 0
547
+ },
548
+ "Namespace": {
549
+ "title": "Namespace",
550
+ "description": "Scopes one application's records within a context, so several tools can share a context without colliding — `openvtc`, `cnm`, an agent runtime. The maintainer MUST NOT interpret the value; it is an opaque partition name. Namespaces are first-come and unreserved, so an application SHOULD pick a stable, specific one: a future per-namespace ACL would grant on this exact string, which makes renaming a namespace a migration rather than an edit.",
551
+ "type": "string",
552
+ "minLength": 1,
553
+ "maxLength": 64,
554
+ "pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
555
+ }
556
+ }
557
+ } as const;
558
+
559
+ /**
560
+ * SPEC.md §7.2 policy for the request variant, from this specification's
561
+ * front matter. Pass to `consumeInbound` — items 5b, 7 and 8 are
562
+ * per-specification and cannot be derived from the document alone, and
563
+ * item 2 needs the schema this carries.
564
+ */
565
+ export const SPEC = {
566
+ typeUri: TYPE_URI,
567
+ isBearer: false,
568
+ isProofRequired: true,
569
+ isRecipientRequired: true,
570
+ payloadSchema: PAYLOAD_SCHEMA,
571
+ } as const;
572
+
573
+ /**
574
+ * SPEC.md §7.2 policy for the success-response variant. `isRecipientRequired`
575
+ * tracks the *issuer* party's requirement because a response swaps the
576
+ * parties (§7.3 item 5).
577
+ */
578
+ export const RESPONSE_SPEC = {
579
+ typeUri: RESPONSE_TYPE_URI,
580
+ isBearer: false,
581
+ isProofRequired: true,
582
+ isRecipientRequired: true,
583
+ payloadSchema: RESPONSE_PAYLOAD_SCHEMA,
584
+ } as const;