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.
- package/README.md +101 -11
- package/dist/bin/run-dmcp.d.ts +2 -0
- package/dist/bin/run-dmcp.js +55 -0
- package/dist/db/connection.d.ts +32 -0
- package/dist/db/connection.js +38 -16
- package/dist/db/schema.d.ts +29 -1
- package/dist/db/schema.js +594 -10
- package/dist/http/server.js +25 -4
- package/dist/index.d.ts +69 -2
- package/dist/index.js +262 -92
- package/dist/mcp-server.d.ts +49 -0
- package/dist/mcp-server.js +127 -0
- package/dist/reader/turnReader.d.ts +185 -0
- package/dist/reader/turnReader.js +288 -0
- package/dist/register/batch.js +5 -79
- package/dist/register/mcp-resources.d.ts +9 -0
- package/dist/register/mcp-resources.js +16 -62
- package/dist/register/render.d.ts +17 -0
- package/dist/register/render.js +50 -0
- package/dist/register/resolve.d.ts +14 -0
- package/dist/register/resolve.js +102 -0
- package/dist/register/resources.js +13 -6
- package/dist/register/timeline.d.ts +2 -0
- package/dist/register/timeline.js +311 -0
- package/dist/rpg/index.d.ts +29 -0
- package/dist/rpg/index.js +55 -0
- package/dist/rpg/register/abilities.d.ts +2 -0
- package/dist/rpg/register/abilities.js +165 -0
- package/dist/rpg/register/batch.d.ts +2 -0
- package/dist/rpg/register/batch.js +92 -0
- package/dist/rpg/register/combat.d.ts +2 -0
- package/dist/rpg/register/combat.js +207 -0
- package/dist/rpg/register/mcp-prompts.d.ts +2 -0
- package/dist/rpg/register/mcp-prompts.js +684 -0
- package/dist/rpg/register/mcp-resources.d.ts +2 -0
- package/dist/rpg/register/mcp-resources.js +61 -0
- package/dist/rpg/register/quests.d.ts +2 -0
- package/dist/rpg/register/quests.js +118 -0
- package/dist/rpg/register/status.d.ts +2 -0
- package/dist/rpg/register/status.js +130 -0
- package/dist/rpg/register/tables.d.ts +2 -0
- package/dist/rpg/register/tables.js +146 -0
- package/dist/rpg/tools/ability.d.ts +48 -0
- package/dist/rpg/tools/ability.js +238 -0
- package/dist/rpg/tools/combat.d.ts +13 -0
- package/dist/rpg/tools/combat.js +195 -0
- package/dist/rpg/tools/dice.d.ts +23 -0
- package/dist/rpg/tools/dice.js +111 -0
- package/dist/rpg/tools/quest.d.ts +34 -0
- package/dist/rpg/tools/quest.js +164 -0
- package/dist/rpg/tools/status.d.ts +36 -0
- package/dist/rpg/tools/status.js +218 -0
- package/dist/rpg/tools/tables.d.ts +33 -0
- package/dist/rpg/tools/tables.js +209 -0
- package/dist/schemas/index.d.ts +12 -12
- package/dist/timeline/adjudication.d.ts +150 -0
- package/dist/timeline/adjudication.js +174 -0
- package/dist/timeline/changes.d.ts +108 -0
- package/dist/timeline/changes.js +169 -0
- package/dist/timeline/checkpoint.d.ts +69 -0
- package/dist/timeline/checkpoint.js +131 -0
- package/dist/timeline/clock.d.ts +89 -0
- package/dist/timeline/clock.js +173 -0
- package/dist/timeline/constrained.d.ts +220 -0
- package/dist/timeline/constrained.js +671 -0
- package/dist/timeline/export.d.ts +181 -0
- package/dist/timeline/export.js +339 -0
- package/dist/timeline/irreversible.d.ts +87 -0
- package/dist/timeline/irreversible.js +108 -0
- package/dist/timeline/kinds.d.ts +14 -0
- package/dist/timeline/kinds.js +22 -0
- package/dist/timeline/narration.d.ts +175 -0
- package/dist/timeline/narration.js +259 -0
- package/dist/timeline/projection.d.ts +97 -0
- package/dist/timeline/projection.js +330 -0
- package/dist/timeline/provenance.d.ts +66 -0
- package/dist/timeline/provenance.js +45 -0
- package/dist/timeline/registry.d.ts +95 -0
- package/dist/timeline/registry.js +124 -0
- package/dist/timeline/render.d.ts +121 -0
- package/dist/timeline/render.js +187 -0
- package/dist/timeline/replay.d.ts +86 -0
- package/dist/timeline/replay.js +126 -0
- package/dist/timeline/resolve.d.ts +262 -0
- package/dist/timeline/resolve.js +226 -0
- package/dist/timeline/schema.d.ts +13 -0
- package/dist/timeline/schema.js +264 -0
- package/dist/timeline/t.d.ts +80 -0
- package/dist/timeline/t.js +37 -0
- package/dist/tools/audio.js +13 -9
- package/dist/tools/constraint.d.ts +44 -80
- package/dist/tools/constraint.js +115 -124
- package/dist/tools/game.js +33 -1
- package/dist/tools/images.js +17 -10
- package/dist/tools/relationship.d.ts +83 -2
- package/dist/tools/relationship.js +139 -62
- package/dist/tools/resource.d.ts +33 -8
- package/dist/tools/resource.js +106 -153
- package/dist/tools/time.js +18 -3
- package/dist/types/index.d.ts +20 -2
- package/dist/utils/media-path.d.ts +52 -0
- package/dist/utils/media-path.js +106 -0
- package/dist/utils/output-schemas.d.ts +594 -3
- package/dist/utils/output-schemas.js +4 -1
- package/dist/utils/webui.d.ts +32 -0
- package/dist/utils/webui.js +54 -1
- package/package.json +25 -5
- package/dist/__tests__/engineVocabulary.test.d.ts +0 -1
- package/dist/__tests__/engineVocabulary.test.js +0 -147
- package/dist/db/__tests__/connection.test.d.ts +0 -1
- package/dist/db/__tests__/connection.test.js +0 -72
- package/dist/db/__tests__/testDb.d.ts +0 -33
- package/dist/db/__tests__/testDb.js +0 -41
- package/dist/test-setup.d.ts +0 -1
- package/dist/test-setup.js +0 -13
- package/dist/tools/__tests__/audio.test.d.ts +0 -1
- package/dist/tools/__tests__/audio.test.js +0 -59
- package/dist/tools/__tests__/conserved.test.d.ts +0 -1
- package/dist/tools/__tests__/conserved.test.js +0 -488
- package/dist/tools/__tests__/constraint.test.d.ts +0 -1
- package/dist/tools/__tests__/constraint.test.js +0 -212
- package/dist/tools/__tests__/expiry-consequences.test.d.ts +0 -1
- package/dist/tools/__tests__/expiry-consequences.test.js +0 -110
- package/dist/tools/__tests__/images.test.d.ts +0 -1
- package/dist/tools/__tests__/images.test.js +0 -59
- package/dist/tools/__tests__/relationship.test.d.ts +0 -1
- package/dist/tools/__tests__/relationship.test.js +0 -132
- package/dist/tools/__tests__/resource-constraints.test.d.ts +0 -1
- package/dist/tools/__tests__/resource-constraints.test.js +0 -131
- package/dist/tools/__tests__/resource.test.d.ts +0 -1
- package/dist/tools/__tests__/resource.test.js +0 -190
- package/dist/tools/__tests__/time.test.d.ts +0 -1
- package/dist/tools/__tests__/time.test.js +0 -404
- package/dist/tools/__tests__/timers.test.d.ts +0 -1
- package/dist/tools/__tests__/timers.test.js +0 -426
- package/dist/tools/__tests__/world.test.d.ts +0 -1
- package/dist/tools/__tests__/world.test.js +0 -70
- package/dist/utils/__tests__/json.test.d.ts +0 -1
- package/dist/utils/__tests__/json.test.js +0 -55
- package/dist/utils/__tests__/validation.test.d.ts +0 -1
- 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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
246
|
-
//
|
|
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 = ?,
|
|
320
|
+
SET relationship_type = ?, label = ?, notes = ?, updated_at = ?
|
|
251
321
|
WHERE id = ?
|
|
252
|
-
`).run(newType,
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
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: {
|
package/dist/tools/resource.d.ts
CHANGED
|
@@ -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 --
|
|
44
|
-
* update_resource_value against such a resource specifically because
|
|
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
|
|
73
|
-
* mutually exclusive per resource means which one to use
|
|
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[];
|