run-dmcp 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +101 -11
  2. package/dist/bin/run-dmcp.d.ts +2 -0
  3. package/dist/bin/run-dmcp.js +55 -0
  4. package/dist/db/connection.d.ts +32 -0
  5. package/dist/db/connection.js +38 -16
  6. package/dist/db/schema.d.ts +29 -1
  7. package/dist/db/schema.js +594 -10
  8. package/dist/http/server.js +25 -4
  9. package/dist/index.d.ts +69 -2
  10. package/dist/index.js +262 -92
  11. package/dist/mcp-server.d.ts +49 -0
  12. package/dist/mcp-server.js +127 -0
  13. package/dist/reader/turnReader.d.ts +185 -0
  14. package/dist/reader/turnReader.js +288 -0
  15. package/dist/register/batch.js +5 -79
  16. package/dist/register/mcp-resources.d.ts +9 -0
  17. package/dist/register/mcp-resources.js +16 -62
  18. package/dist/register/render.d.ts +17 -0
  19. package/dist/register/render.js +50 -0
  20. package/dist/register/resolve.d.ts +14 -0
  21. package/dist/register/resolve.js +102 -0
  22. package/dist/register/resources.js +13 -6
  23. package/dist/register/timeline.d.ts +2 -0
  24. package/dist/register/timeline.js +311 -0
  25. package/dist/rpg/index.d.ts +29 -0
  26. package/dist/rpg/index.js +55 -0
  27. package/dist/rpg/register/abilities.d.ts +2 -0
  28. package/dist/rpg/register/abilities.js +165 -0
  29. package/dist/rpg/register/batch.d.ts +2 -0
  30. package/dist/rpg/register/batch.js +92 -0
  31. package/dist/rpg/register/combat.d.ts +2 -0
  32. package/dist/rpg/register/combat.js +207 -0
  33. package/dist/rpg/register/mcp-prompts.d.ts +2 -0
  34. package/dist/rpg/register/mcp-prompts.js +684 -0
  35. package/dist/rpg/register/mcp-resources.d.ts +2 -0
  36. package/dist/rpg/register/mcp-resources.js +61 -0
  37. package/dist/rpg/register/quests.d.ts +2 -0
  38. package/dist/rpg/register/quests.js +118 -0
  39. package/dist/rpg/register/status.d.ts +2 -0
  40. package/dist/rpg/register/status.js +130 -0
  41. package/dist/rpg/register/tables.d.ts +2 -0
  42. package/dist/rpg/register/tables.js +146 -0
  43. package/dist/rpg/tools/ability.d.ts +48 -0
  44. package/dist/rpg/tools/ability.js +238 -0
  45. package/dist/rpg/tools/combat.d.ts +13 -0
  46. package/dist/rpg/tools/combat.js +195 -0
  47. package/dist/rpg/tools/dice.d.ts +23 -0
  48. package/dist/rpg/tools/dice.js +111 -0
  49. package/dist/rpg/tools/quest.d.ts +34 -0
  50. package/dist/rpg/tools/quest.js +164 -0
  51. package/dist/rpg/tools/status.d.ts +36 -0
  52. package/dist/rpg/tools/status.js +218 -0
  53. package/dist/rpg/tools/tables.d.ts +33 -0
  54. package/dist/rpg/tools/tables.js +209 -0
  55. package/dist/schemas/index.d.ts +12 -12
  56. package/dist/timeline/adjudication.d.ts +150 -0
  57. package/dist/timeline/adjudication.js +174 -0
  58. package/dist/timeline/changes.d.ts +108 -0
  59. package/dist/timeline/changes.js +169 -0
  60. package/dist/timeline/checkpoint.d.ts +69 -0
  61. package/dist/timeline/checkpoint.js +131 -0
  62. package/dist/timeline/clock.d.ts +89 -0
  63. package/dist/timeline/clock.js +173 -0
  64. package/dist/timeline/constrained.d.ts +220 -0
  65. package/dist/timeline/constrained.js +671 -0
  66. package/dist/timeline/export.d.ts +181 -0
  67. package/dist/timeline/export.js +339 -0
  68. package/dist/timeline/irreversible.d.ts +87 -0
  69. package/dist/timeline/irreversible.js +108 -0
  70. package/dist/timeline/kinds.d.ts +14 -0
  71. package/dist/timeline/kinds.js +22 -0
  72. package/dist/timeline/narration.d.ts +175 -0
  73. package/dist/timeline/narration.js +259 -0
  74. package/dist/timeline/projection.d.ts +97 -0
  75. package/dist/timeline/projection.js +330 -0
  76. package/dist/timeline/provenance.d.ts +66 -0
  77. package/dist/timeline/provenance.js +45 -0
  78. package/dist/timeline/registry.d.ts +95 -0
  79. package/dist/timeline/registry.js +124 -0
  80. package/dist/timeline/render.d.ts +121 -0
  81. package/dist/timeline/render.js +187 -0
  82. package/dist/timeline/replay.d.ts +86 -0
  83. package/dist/timeline/replay.js +126 -0
  84. package/dist/timeline/resolve.d.ts +262 -0
  85. package/dist/timeline/resolve.js +226 -0
  86. package/dist/timeline/schema.d.ts +13 -0
  87. package/dist/timeline/schema.js +264 -0
  88. package/dist/timeline/t.d.ts +80 -0
  89. package/dist/timeline/t.js +37 -0
  90. package/dist/tools/audio.js +13 -9
  91. package/dist/tools/constraint.d.ts +44 -80
  92. package/dist/tools/constraint.js +115 -124
  93. package/dist/tools/game.js +33 -1
  94. package/dist/tools/images.js +17 -10
  95. package/dist/tools/relationship.d.ts +83 -2
  96. package/dist/tools/relationship.js +139 -62
  97. package/dist/tools/resource.d.ts +33 -8
  98. package/dist/tools/resource.js +106 -153
  99. package/dist/tools/time.js +18 -3
  100. package/dist/types/index.d.ts +20 -2
  101. package/dist/utils/media-path.d.ts +52 -0
  102. package/dist/utils/media-path.js +106 -0
  103. package/dist/utils/output-schemas.d.ts +594 -3
  104. package/dist/utils/output-schemas.js +4 -1
  105. package/dist/utils/webui.d.ts +32 -0
  106. package/dist/utils/webui.js +54 -1
  107. package/package.json +25 -5
  108. package/dist/__tests__/engineVocabulary.test.d.ts +0 -1
  109. package/dist/__tests__/engineVocabulary.test.js +0 -147
  110. package/dist/db/__tests__/connection.test.d.ts +0 -1
  111. package/dist/db/__tests__/connection.test.js +0 -72
  112. package/dist/db/__tests__/testDb.d.ts +0 -33
  113. package/dist/db/__tests__/testDb.js +0 -41
  114. package/dist/test-setup.d.ts +0 -1
  115. package/dist/test-setup.js +0 -13
  116. package/dist/tools/__tests__/audio.test.d.ts +0 -1
  117. package/dist/tools/__tests__/audio.test.js +0 -59
  118. package/dist/tools/__tests__/conserved.test.d.ts +0 -1
  119. package/dist/tools/__tests__/conserved.test.js +0 -488
  120. package/dist/tools/__tests__/constraint.test.d.ts +0 -1
  121. package/dist/tools/__tests__/constraint.test.js +0 -212
  122. package/dist/tools/__tests__/expiry-consequences.test.d.ts +0 -1
  123. package/dist/tools/__tests__/expiry-consequences.test.js +0 -110
  124. package/dist/tools/__tests__/images.test.d.ts +0 -1
  125. package/dist/tools/__tests__/images.test.js +0 -59
  126. package/dist/tools/__tests__/relationship.test.d.ts +0 -1
  127. package/dist/tools/__tests__/relationship.test.js +0 -132
  128. package/dist/tools/__tests__/resource-constraints.test.d.ts +0 -1
  129. package/dist/tools/__tests__/resource-constraints.test.js +0 -131
  130. package/dist/tools/__tests__/resource.test.d.ts +0 -1
  131. package/dist/tools/__tests__/resource.test.js +0 -190
  132. package/dist/tools/__tests__/time.test.d.ts +0 -1
  133. package/dist/tools/__tests__/time.test.js +0 -404
  134. package/dist/tools/__tests__/timers.test.d.ts +0 -1
  135. package/dist/tools/__tests__/timers.test.js +0 -426
  136. package/dist/tools/__tests__/world.test.d.ts +0 -1
  137. package/dist/tools/__tests__/world.test.js +0 -70
  138. package/dist/utils/__tests__/json.test.d.ts +0 -1
  139. package/dist/utils/__tests__/json.test.js +0 -55
  140. package/dist/utils/__tests__/validation.test.d.ts +0 -1
  141. package/dist/utils/__tests__/validation.test.js +0 -90
@@ -1,6 +1,29 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
2
  import { getDatabase, withTransaction } from "../db/connection.js";
3
3
  import { validateGameExists } from "./game.js";
4
+ import { writeConstrainedValue, valueHistory } from "../timeline/constrained.js";
5
+ /**
6
+ * Maps a timeline `ValueTransition` (src/timeline/constrained.ts) onto the
7
+ * public `RelationshipChange` shape every existing caller of
8
+ * modifyRelationship()/updateRelationshipValue()/getRelationshipHistory()
9
+ * already expects. Mirrors transitionToResourceChange() in
10
+ * src/tools/resource.ts exactly, minus `delta` -- RelationshipChange has no
11
+ * `delta` field (src/types/index.ts) and never has, so none is invented
12
+ * here. `id` prefers the annotation event's id, falling back to the fact id
13
+ * for a transition no constrained write annotated; `timestamp` prefers the
14
+ * wall-clock `at` the choke point stamped, falling back to the timeline
15
+ * coordinate `t` for a transition with no wall-clock moment to report.
16
+ */
17
+ function transitionToRelationshipChange(transition) {
18
+ return {
19
+ id: transition.eventId ?? transition.factId ?? "",
20
+ relationshipId: transition.entityId,
21
+ previousValue: transition.previousValue,
22
+ newValue: transition.newValue,
23
+ reason: transition.reason,
24
+ timestamp: transition.at ?? String(transition.t),
25
+ };
26
+ }
4
27
  export function createRelationship(params) {
5
28
  // Validate game exists to prevent orphaned records
6
29
  validateGameExists(params.gameId);
@@ -73,6 +96,19 @@ export function getRelationshipBetween(gameId, sourceId, targetId, relationshipT
73
96
  updatedAt: row.updated_at,
74
97
  };
75
98
  }
99
+ /**
100
+ * Metadata updater that also accepts a new value, written by a single
101
+ * direct UPDATE -- deliberately NOT routed through writeConstrainedValue()
102
+ * (src/timeline/constrained.ts). Its value write therefore lands as an
103
+ * UNANNOTATED transition in valueHistory()/getRelationshipHistory() below
104
+ * (reason: null, eventId: null) rather than one a constrained write
105
+ * stamped -- which is still strictly MORE history than the old
106
+ * relationship_history table ever held for this path, since nothing wrote
107
+ * there for a plain updateRelationship() call either. Mirrors
108
+ * updateResource() in src/tools/resource.ts, whose own value-adjacent write
109
+ * (re-clamping on a bounds change) is likewise a direct column write, not a
110
+ * choke-point one.
111
+ */
76
112
  export function updateRelationship(id, updates) {
77
113
  const db = getDatabase();
78
114
  const current = getRelationship(id);
@@ -97,25 +133,34 @@ export function updateRelationship(id, updates) {
97
133
  updatedAt: now,
98
134
  };
99
135
  }
100
- function logRelationshipChange(relationshipId, previousValue, newValue, reason) {
101
- const db = getDatabase();
102
- const id = uuidv4();
103
- const now = new Date().toISOString();
104
- db.prepare(`
105
- INSERT INTO relationship_history (id, relationship_id, previous_value, new_value, reason, timestamp)
106
- VALUES (?, ?, ?, ?, ?, ?)
107
- `).run(id, relationshipId, previousValue, newValue, reason, now);
108
- return {
109
- id,
110
- relationshipId,
111
- previousValue,
112
- newValue,
113
- reason,
114
- timestamp: now,
115
- };
116
- }
136
+ /**
137
+ * Modify a relationship's value by a delta, with optional bounds. Delegates
138
+ * the value write entirely to writeConstrainedValue() (src/timeline/
139
+ * constrained.ts) -- the one choke point every constrained numeric fact key
140
+ * writes through, mirroring updateResourceValue() in src/tools/resource.ts.
141
+ * The resolve/check/clamp/write/annotate sequence, and the atomicity of the
142
+ * write and its audit trail, all live there now.
143
+ *
144
+ * Logs unconditionally, including for a zero delta -- exactly as this
145
+ * function always has. The choke point itself already handles a no-op
146
+ * write: it opens no new fact (there is nothing to version when the value
147
+ * doesn't move), but it still writes the annotation event, and
148
+ * valueHistory()/getRelationshipHistory() below surface that event as a
149
+ * history row regardless. So a zero-delta call still produces a row with no
150
+ * extra code here -- see conserved.test.ts's "logged even though nothing
151
+ * moved" assertions on the resource side of the same mechanism.
152
+ *
153
+ * `updated_at` gets its own UPDATE, in the same withTransaction() as the
154
+ * value write, for the same reason updateRelationshipValue() below writes
155
+ * its metadata separately: the choke point writes ONE column -- the
156
+ * constrained fact key -- and nothing else, because a writer that also
157
+ * touched neighbouring columns would be making policy about them. This
158
+ * function's `updated_at` bump is that policy, so it stays here, where it
159
+ * always was. Dropping it would be a silent regression: listRelationships()
160
+ * orders by `updated_at DESC`, so a relationship modified through this path
161
+ * would stop sorting as recently touched.
162
+ */
117
163
  export function modifyRelationship(params) {
118
- const db = getDatabase();
119
164
  const relationship = getRelationship(params.relationshipId);
120
165
  if (!relationship)
121
166
  return null;
@@ -123,27 +168,23 @@ export function modifyRelationship(params) {
123
168
  if (params.minValue !== undefined && params.maxValue !== undefined && params.minValue > params.maxValue) {
124
169
  throw new Error(`Invalid bounds: minValue (${params.minValue}) cannot be greater than maxValue (${params.maxValue})`);
125
170
  }
126
- const previousValue = relationship.value;
127
- let newValue = previousValue + params.delta;
128
- // Apply bounds (clamp to min first, then max to ensure max takes precedence)
129
- if (params.minValue !== undefined) {
130
- newValue = Math.max(newValue, params.minValue);
131
- }
132
- if (params.maxValue !== undefined) {
133
- newValue = Math.min(newValue, params.maxValue);
134
- }
135
171
  const now = new Date().toISOString();
136
- // The value update and its history row must land together -- otherwise a
137
- // failure between the two leaves a changed relationship value with no
138
- // audit trail explaining why it changed.
139
- const change = withTransaction(() => {
140
- db.prepare(`UPDATE relationships SET value = ?, updated_at = ? WHERE id = ?`)
141
- .run(newValue, now, params.relationshipId);
142
- return logRelationshipChange(params.relationshipId, previousValue, newValue, params.reason || null);
172
+ const transition = withTransaction(() => {
173
+ getDatabase()
174
+ .prepare(`UPDATE relationships SET updated_at = ? WHERE id = ?`)
175
+ .run(now, params.relationshipId);
176
+ return writeConstrainedValue({
177
+ entityId: params.relationshipId,
178
+ key: "value",
179
+ mode: "delta",
180
+ value: params.delta,
181
+ reason: params.reason || null,
182
+ bounds: { minValue: params.minValue ?? null, maxValue: params.maxValue ?? null },
183
+ });
143
184
  });
144
185
  return {
145
- relationship: { ...relationship, value: newValue, updatedAt: now },
146
- change,
186
+ relationship: { ...relationship, value: transition.newValue, updatedAt: now },
187
+ change: transitionToRelationshipChange(transition),
147
188
  };
148
189
  }
149
190
  export function deleteRelationship(id) {
@@ -192,27 +233,53 @@ export function listRelationships(gameId, filter) {
192
233
  updatedAt: row.updated_at,
193
234
  }));
194
235
  }
236
+ /**
237
+ * Every recorded change to a relationship's value, newest first. Built
238
+ * entirely from the timeline (valueHistory() in src/timeline/
239
+ * constrained.ts) -- there is no `relationship_history` table backing this
240
+ * any more (design §5.4 option (C); see the freeze trigger in
241
+ * src/db/schema.ts). Mirrors getResourceHistory() in src/tools/resource.ts
242
+ * exactly, and is a strict superset of what `relationship_history` ever
243
+ * held for the same reason: it also surfaces transitions no constrained
244
+ * write annotated (e.g. updateRelationship()'s direct column write above),
245
+ * which the old table simply never recorded.
246
+ */
195
247
  export function getRelationshipHistory(relationshipId, limit) {
196
- const db = getDatabase();
197
- let query = `SELECT * FROM relationship_history WHERE relationship_id = ? ORDER BY timestamp DESC`;
198
- const params = [relationshipId];
199
- if (limit) {
200
- query += ` LIMIT ?`;
201
- params.push(limit);
202
- }
203
- const rows = db.prepare(query).all(...params);
204
- return rows.map(row => ({
205
- id: row.id,
206
- relationshipId: row.relationship_id,
207
- previousValue: row.previous_value,
208
- newValue: row.new_value,
209
- reason: row.reason,
210
- timestamp: row.timestamp,
211
- }));
248
+ return valueHistory(relationshipId, "value", limit).map(transitionToRelationshipChange);
212
249
  }
213
250
  /**
214
- * Update a relationship value with optional metadata changes. Supports both direct set and delta modes.
215
- * Logs to history when value changes.
251
+ * Update a relationship value with optional metadata changes. Supports both
252
+ * direct set and delta modes. Logs to history when the value changes; no
253
+ * history row (and `change: null`) when it doesn't -- that "no-op means no
254
+ * row" contract is this function's own, distinct from modifyRelationship()
255
+ * above, which always logs (see its doc comment). The choke point itself
256
+ * ALWAYS leaves a trace of a write, including a no-op one (an annotation
257
+ * event with no fact behind it -- see applyLiveWrite() in
258
+ * src/timeline/constrained.ts), so writeConstrainedValue() below is called
259
+ * ONLY when newValue !== previousValue -- routing a genuine no-op through it
260
+ * would put a row in getRelationshipHistory() that this contract says must
261
+ * not appear.
262
+ *
263
+ * `newValue` is computed and clamped here, BEFORE the choke-point call, for
264
+ * two reasons: first, to make that changed/unchanged decision at all;
265
+ * second, so the value handed to writeConstrainedValue() (mode: "set") is
266
+ * already the caller's real intent -- the choke point's own clamp against
267
+ * the same `bounds` is then a no-op on an already-clamped number, and its
268
+ * constraint check (assertConstraintsAllow(), src/timeline/constrained.ts)
269
+ * still sees a real, meaningful intended value rather than a raw delta.
270
+ *
271
+ * The metadata columns (relationship_type, label, notes, updated_at) are
272
+ * written by their own UPDATE, separate from the value write below, but
273
+ * both run inside one withTransaction() so the whole call is still one
274
+ * atomic unit -- exactly as before, just as two statements against
275
+ * `relationships` instead of one. That is a real, visible consequence of
276
+ * routing the value column through the one choke point every constrained
277
+ * write goes through: each statement fires the table's own projection
278
+ * trigger (projection.ts) independently, so a value-changing call now
279
+ * advances the timeline's `t` twice and logs two `relationship.updated`
280
+ * events instead of one. One write path for "what did this value used to
281
+ * be" is worth that -- see constrained.ts's own header comment on why a
282
+ * second write path is the failure this project keeps rediscovering.
216
283
  */
217
284
  export function updateRelationshipValue(params) {
218
285
  const db = getDatabase();
@@ -242,19 +309,29 @@ export function updateRelationshipValue(params) {
242
309
  const newType = params.relationshipType ?? relationship.relationshipType;
243
310
  const newLabel = params.label !== undefined ? params.label : relationship.label;
244
311
  const newNotes = params.notes ?? relationship.notes;
245
- // The value/metadata update and its (conditional) history row must land
246
- // together, for the same reason as modifyRelationship() above.
312
+ const bounds = { minValue: params.minValue ?? null, maxValue: params.maxValue ?? null };
313
+ // The metadata update and the (conditional) value write must land
314
+ // together, for the same reason as modifyRelationship() above -- a
315
+ // failure between the two must never leave a changed value with no
316
+ // metadata update applied, or vice versa.
247
317
  const change = withTransaction(() => {
248
318
  db.prepare(`
249
319
  UPDATE relationships
250
- SET relationship_type = ?, value = ?, label = ?, notes = ?, updated_at = ?
320
+ SET relationship_type = ?, label = ?, notes = ?, updated_at = ?
251
321
  WHERE id = ?
252
- `).run(newType, newValue, newLabel, newNotes, now, params.relationshipId);
253
- // Log to history if value changed
254
- if (newValue !== previousValue) {
255
- return logRelationshipChange(params.relationshipId, previousValue, newValue, params.reason || null);
322
+ `).run(newType, newLabel, newNotes, now, params.relationshipId);
323
+ if (newValue === previousValue) {
324
+ return null;
256
325
  }
257
- return null;
326
+ const transition = writeConstrainedValue({
327
+ entityId: params.relationshipId,
328
+ key: "value",
329
+ mode: "set",
330
+ value: newValue,
331
+ reason: params.reason || null,
332
+ bounds,
333
+ });
334
+ return transitionToRelationshipChange(transition);
258
335
  });
259
336
  return {
260
337
  relationship: {
@@ -1,7 +1,7 @@
1
1
  import type { Resource, ResourceChange } from "../types/index.js";
2
2
  export declare function createResource(params: {
3
3
  gameId: string;
4
- ownerType: "game" | "character";
4
+ ownerType: "game" | "character" | "faction" | "location";
5
5
  ownerId?: string;
6
6
  name: string;
7
7
  description?: string;
@@ -20,13 +20,21 @@ export declare function updateResource(id: string, updates: {
20
20
  }): Resource | null;
21
21
  export declare function deleteResource(id: string): boolean;
22
22
  export declare function listResources(gameId: string, filter?: {
23
- ownerType?: "game" | "character";
23
+ ownerType?: "game" | "character" | "faction" | "location";
24
24
  ownerId?: string;
25
25
  category?: string;
26
26
  }): Resource[];
27
27
  /**
28
28
  * Update a resource's value - either by delta or absolute set.
29
29
  * Use mode: "delta" to add/subtract, mode: "set" to set an absolute value.
30
+ *
31
+ * Delegates entirely to writeConstrainedValue() (src/timeline/constrained.ts)
32
+ * -- the resolve/check/clamp/write/annotate sequence, and the atomicity of
33
+ * the write and its audit trail, all live there now. This function's own job
34
+ * is narrower than it used to be: translate the resource-shaped call into
35
+ * the generic (entityId, factKey) one, and translate the generic
36
+ * ValueTransition result back into the Resource/ResourceChange shapes every
37
+ * existing caller already expects.
30
38
  */
31
39
  export declare function updateResourceValue(params: {
32
40
  resourceId: string;
@@ -40,9 +48,9 @@ export declare function updateResourceValue(params: {
40
48
  /**
41
49
  * Move `amount` from one resource to another, atomically. This is the ONLY
42
50
  * write path for a resource that is a member of a declared 'conserved'
43
- * constraint -- checkResourceConstraints() (constraint.ts) rejects
44
- * update_resource_value against such a resource specifically because a
45
- * single-resource write can't express where the counterpart delta comes
51
+ * constraint -- assertConstraintsAllow() (src/timeline/constrained.ts)
52
+ * rejects update_resource_value against such a resource specifically because
53
+ * a single-resource write can't express where the counterpart delta comes
46
54
  * from. This function is that counterpart-carrying write.
47
55
  *
48
56
  * WHY AN EXPLICIT TRANSFER TOOL, NOT A BALANCED MULTI-RESOURCE WRITE:
@@ -69,15 +77,22 @@ export declare function updateResourceValue(params: {
69
77
  * be members of the SAME declared 'conserved' constraint. This is not a
70
78
  * general "move value between any two resources" tool -- for anything not
71
79
  * under a 'conserved' constraint, update_resource_value remains the right
72
- * tool (see checkResourceConstraints()). Keeping the two write paths
73
- * mutually exclusive per resource means which one to use is never
74
- * ambiguous.
80
+ * tool (see assertConstraintsAllow() in src/timeline/constrained.ts). Keeping
81
+ * the two write paths mutually exclusive per resource means which one to use
82
+ * is never ambiguous.
75
83
  *
76
84
  * Never clamps. Clamping one side of a transfer would apply an uneven delta
77
85
  * -- the source would lose less (or the destination gain less) than the
78
86
  * other side moved by, silently creating or destroying value -- so any
79
87
  * bound violation on either side rejects the whole transfer instead,
80
88
  * regardless of whether a 'bounded' constraint is separately declared.
89
+ *
90
+ * Keeps its own argument validation (self-transfer, non-finite, negative,
91
+ * not-found) -- that is about resource IDENTITY, not about the declared
92
+ * constraint family, so it stays here rather than moving into
93
+ * transferConstrainedValue() (src/timeline/constrained.ts), which delegates
94
+ * the actual membership check, the bounded/monotonic checks, the never-clamp
95
+ * bounds rejection, and both atomic writes.
81
96
  */
82
97
  export declare function transferResourceValue(params: {
83
98
  fromResourceId: string;
@@ -90,4 +105,14 @@ export declare function transferResourceValue(params: {
90
105
  fromChange: ResourceChange;
91
106
  toChange: ResourceChange;
92
107
  };
108
+ /**
109
+ * Every recorded change to a resource's value, newest first. Built entirely
110
+ * from the timeline (valueHistory() in src/timeline/constrained.ts) -- there
111
+ * is no `resource_history` table backing this any more (design §5.4 option
112
+ * (C); see the freeze trigger in src/db/schema.ts). This is a strict
113
+ * superset of what `resource_history` ever held: it also surfaces
114
+ * transitions no constrained write annotated (a direct column write, a
115
+ * bounds re-clamp, a startup reconciliation), which the old table simply
116
+ * never recorded.
117
+ */
93
118
  export declare function getResourceHistory(resourceId: string, limit?: number): ResourceChange[];