@adam0white/human-framework 2.9.0 → 2.10.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/dist/agenda/agenda.js +1 -1
- package/dist/beliefs/beliefs.d.ts +45 -1
- package/dist/beliefs/beliefs.js +208 -4
- package/dist/cognition/cognition.js +2 -2
- package/dist/conscience/conscience.d.ts +7 -3
- package/dist/conscience/conscience.js +5 -1
- package/dist/conversation/conversation.d.ts +4 -0
- package/dist/conversation/conversation.js +25 -0
- package/dist/core/math.d.ts +1 -0
- package/dist/core/math.js +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/memory/memory.js +4 -1
- package/dist/migrate.js +18 -1
- package/dist/person.js +150 -100
- package/dist/prospection/prospection.js +8 -2
- package/dist/restore.d.ts +9 -0
- package/dist/restore.js +22 -0
- package/dist/sim/sim.d.ts +7 -2
- package/dist/sim/sim.js +118 -93
- package/dist/social/impressions.d.ts +31 -2
- package/dist/social/impressions.js +38 -1
- package/dist/social/social.d.ts +2 -0
- package/dist/social/social.js +18 -2
- package/dist/types.d.ts +55 -6
- package/dist/types.js +1 -1
- package/dist/will/will.js +94 -65
- package/package.json +1 -1
package/dist/agenda/agenda.js
CHANGED
|
@@ -489,7 +489,7 @@ function deadlinePressure(g, now) {
|
|
|
489
489
|
return 1 + AGENDA_DEFAULTS.goalDeadlineBoost * clamp01((now - g.adoptedAt) / span);
|
|
490
490
|
}
|
|
491
491
|
/** Shared existing amount and urgency reader; no future knowledge is consulted here. @internal */
|
|
492
|
-
|
|
492
|
+
function goalValue(g, aff, now) {
|
|
493
493
|
const amount = goalAmount(g, aff);
|
|
494
494
|
return amount > 0
|
|
495
495
|
? g.importance * clamp01(amount * AGENDA_DEFAULTS.goalAmountGain) * deadlinePressure(g, now)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Belief, EntityId, Minute, Percept, Person, Unit } from '../types.ts';
|
|
1
|
+
import type { Belief, BeliefProvenance, EntityId, Minute, Percept, Person, Unit } from '../types.ts';
|
|
2
2
|
export declare const BELIEF_DEFAULTS: {
|
|
3
3
|
maxBeliefs: number;
|
|
4
4
|
maxSources: number;
|
|
@@ -17,6 +17,9 @@ export declare const BELIEF_DEFAULTS: {
|
|
|
17
17
|
/** Trust change on confirmation: gain toward 1, loss toward 0 (loss > gain). */
|
|
18
18
|
trustGain: number;
|
|
19
19
|
trustLoss: number;
|
|
20
|
+
/** Loss of source trust after attending incompatible accounts from that same source. */
|
|
21
|
+
contradictionLoss: number;
|
|
22
|
+
maxContradictions: number;
|
|
20
23
|
/** Half-life of log-odds drift toward 0. */
|
|
21
24
|
driftHalfLife: number;
|
|
22
25
|
attentionBase: number;
|
|
@@ -39,7 +42,29 @@ export interface AttendContext {
|
|
|
39
42
|
}
|
|
40
43
|
/** Attention as limited capacity: keep the K most relevant percepts plus any that cannot be ignored. */
|
|
41
44
|
export declare function attend(p: Person, percepts: Percept[], ctx: AttendContext): Percept[];
|
|
45
|
+
/** Information-source trust, independent of relationship trust and advising-voice trust. */
|
|
42
46
|
export declare function trustOf(p: Person, sourceId: EntityId): Unit;
|
|
47
|
+
/**
|
|
48
|
+
* Set authored trust in an information source, clamped to 0..1. Writes only `memory.sourceTrust`;
|
|
49
|
+
* it does not change relationship trust or advising-voice trust. Nonfinite trust and self ids throw.
|
|
50
|
+
* Later `believe` (including testimony through `perceive`) reads this trust; `confirm` recalibrates it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function seedSourceTrust(p: Person, sourceId: EntityId, trust: Unit): Unit;
|
|
53
|
+
/**
|
|
54
|
+
* Set or replace an authored belief without applying source trust or recording an observation.
|
|
55
|
+
* `credence` is the probability that `value` holds, clamped to 0..1 and stored as bounded signed
|
|
56
|
+
* log-odds. `at` defaults to the person's current minute. Nonfinite credence or time throws.
|
|
57
|
+
* Only `memory.beliefs` changes, with ordinary belief eviction. An omitted source leaves no sources;
|
|
58
|
+
* a named source records its claim for later `confirm`, without changing any trust store now. The person's own id
|
|
59
|
+
* and 'self' are refused (they mark observation): use `confirm` for something the person saw.
|
|
60
|
+
* It does not apply reputation to relationships; use `seedTie` to author a relationship.
|
|
61
|
+
*/
|
|
62
|
+
export declare function seedBelief(p: Person, prop: string, spec: {
|
|
63
|
+
value: boolean;
|
|
64
|
+
credence: Unit;
|
|
65
|
+
at?: Minute;
|
|
66
|
+
source?: EntityId;
|
|
67
|
+
}): Belief;
|
|
43
68
|
/** Testimony or inference: add reliability-weighted log-odds evidence for (or against) `prop`. */
|
|
44
69
|
export declare function believe(p: Person, prop: string, value: boolean, confidence: Unit, sourceId: EntityId, now: Minute): Belief;
|
|
45
70
|
export declare function credence(p: Person, prop: string): Unit;
|
|
@@ -67,3 +92,22 @@ export declare function contested(p: Person, prop: string): {
|
|
|
67
92
|
against: EntityId[];
|
|
68
93
|
contested: boolean;
|
|
69
94
|
};
|
|
95
|
+
/** Where this person first got the belief on `prop`, or undefined. */
|
|
96
|
+
export declare function provenanceOf(p: Person, prop: string): BeliefProvenance | undefined;
|
|
97
|
+
export interface ContradictionResult {
|
|
98
|
+
applied: boolean;
|
|
99
|
+
reason?: 'no-account' | 'same-account' | 'already-noted' | 'self' | 'untrusted-reporter';
|
|
100
|
+
before: Unit;
|
|
101
|
+
after: Unit;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The person learns that `sourceId` also gave the account `prop = value` elsewhere, against what that source told
|
|
105
|
+
* them. See the contradiction SCOPE.
|
|
106
|
+
*/
|
|
107
|
+
export declare function contradicted(p: Person, ev: {
|
|
108
|
+
sourceId: EntityId;
|
|
109
|
+
prop: string;
|
|
110
|
+
value: boolean;
|
|
111
|
+
reporterId?: EntityId;
|
|
112
|
+
at?: Minute;
|
|
113
|
+
}): ContradictionResult;
|
package/dist/beliefs/beliefs.js
CHANGED
|
@@ -8,9 +8,24 @@
|
|
|
8
8
|
* gained, the trust-asymmetry finding). It does NOT model motivated reasoning, belief networks or
|
|
9
9
|
* inference between propositions, source memory errors, or social consensus effects; parameters are
|
|
10
10
|
* engineering defaults for game time scales.
|
|
11
|
+
*
|
|
12
|
+
* Three independent stores: `social.relationships[].trust` moves through authored ties, social events
|
|
13
|
+
* (including forgiveness), judged acts and reputation; `will.voices[].trust` moves through followed-advice
|
|
14
|
+
* outcomes, insisting, commands, `noteVoicePromise`, `seedVoice` and `adoptVoiceTrust` (also used by upbringing).
|
|
15
|
+
* This module owns `memory.sourceTrust`: `seedSourceTrust` authors it, `confirm` recalibrates it and
|
|
16
|
+
* `contradicted` reduces it when one source gives incompatible accounts.
|
|
17
|
+
* `believe`, including testimony delivered by `perceive`, weights claims by source trust, read by `trustOf`.
|
|
18
|
+
*
|
|
19
|
+
* SCOPE (Word and witness): optional provenance records the first known origin, direct teller and opaque
|
|
20
|
+
* host lineage of a belief. It does not change credence or decisions, reconstruct a relay graph, verify an
|
|
21
|
+
* origin, or survive belief eviction. Contradiction reduces information-source trust only when a retained
|
|
22
|
+
* first-hand account from that source opposes the newly learned account. Independent sources disagreeing
|
|
23
|
+
* are not a contradiction here. A third-party report is weighted by the reporter's source trust; this does
|
|
24
|
+
* not prove deceit, change the belief, or change relationship or voice trust. Loss and retention limits are
|
|
25
|
+
* engineering defaults, not calibrated effect sizes. Deduplication lasts only while its bounded record stays.
|
|
11
26
|
*/
|
|
12
|
-
import { clamp, clamp01, decay, dpow, expit, logit } from '../core/index.js';
|
|
13
|
-
import { MINUTES_PER_DAY } from '../types.js';
|
|
27
|
+
import { clamp, clamp01, decay, dpow, expit, isNum, isObj, logit } from '../core/index.js';
|
|
28
|
+
import { MAX_MINUTE, MINUTES_PER_DAY } from '../types.js';
|
|
14
29
|
export const BELIEF_DEFAULTS = {
|
|
15
30
|
maxBeliefs: 300,
|
|
16
31
|
maxSources: 6,
|
|
@@ -29,6 +44,9 @@ export const BELIEF_DEFAULTS = {
|
|
|
29
44
|
/** Trust change on confirmation: gain toward 1, loss toward 0 (loss > gain). */
|
|
30
45
|
trustGain: 0.1,
|
|
31
46
|
trustLoss: 0.25,
|
|
47
|
+
/** Loss of source trust after attending incompatible accounts from that same source. */
|
|
48
|
+
contradictionLoss: 0.25,
|
|
49
|
+
maxContradictions: 32,
|
|
32
50
|
/** Half-life of log-odds drift toward 0. */
|
|
33
51
|
driftHalfLife: 45 * MINUTES_PER_DAY,
|
|
34
52
|
// Attention
|
|
@@ -97,10 +115,32 @@ export function attend(p, percepts, ctx) {
|
|
|
97
115
|
}
|
|
98
116
|
return out;
|
|
99
117
|
}
|
|
118
|
+
/** Information-source trust, independent of relationship trust and advising-voice trust. */
|
|
100
119
|
export function trustOf(p, sourceId) {
|
|
101
120
|
if (sourceId === p.id || sourceId === 'self')
|
|
102
121
|
return BELIEF_DEFAULTS.selfTrust;
|
|
103
|
-
|
|
122
|
+
// Own entries only: an id such as `constructor` or `__proto__` must not read an inherited property.
|
|
123
|
+
const own = Object.hasOwn(p.memory.sourceTrust, sourceId) ? p.memory.sourceTrust[sourceId] : undefined;
|
|
124
|
+
return typeof own === 'number' ? own : BELIEF_DEFAULTS.defaultTrust;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Set authored trust in an information source, clamped to 0..1. Writes only `memory.sourceTrust`;
|
|
128
|
+
* it does not change relationship trust or advising-voice trust. Nonfinite trust and self ids throw.
|
|
129
|
+
* Later `believe` (including testimony through `perceive`) reads this trust; `confirm` recalibrates it.
|
|
130
|
+
*/
|
|
131
|
+
export function seedSourceTrust(p, sourceId, trust) {
|
|
132
|
+
if (!Number.isFinite(trust))
|
|
133
|
+
throw new Error('human: source trust must be finite');
|
|
134
|
+
if (sourceId === p.id || sourceId === 'self')
|
|
135
|
+
throw new Error('human: self trust cannot be seeded');
|
|
136
|
+
const value = clamp01(trust);
|
|
137
|
+
Object.defineProperty(p.memory.sourceTrust, sourceId, {
|
|
138
|
+
value,
|
|
139
|
+
writable: true,
|
|
140
|
+
enumerable: true,
|
|
141
|
+
configurable: true,
|
|
142
|
+
});
|
|
143
|
+
return value;
|
|
104
144
|
}
|
|
105
145
|
/** Testimony weight from trust: 0 at or below the floor, never negative, so low trust alone never flips a claim. @internal */
|
|
106
146
|
export function testimonyWeight(trust) {
|
|
@@ -141,6 +181,31 @@ function ensureBelief(p, prop, now) {
|
|
|
141
181
|
}
|
|
142
182
|
return b;
|
|
143
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Set or replace an authored belief without applying source trust or recording an observation.
|
|
186
|
+
* `credence` is the probability that `value` holds, clamped to 0..1 and stored as bounded signed
|
|
187
|
+
* log-odds. `at` defaults to the person's current minute. Nonfinite credence or time throws.
|
|
188
|
+
* Only `memory.beliefs` changes, with ordinary belief eviction. An omitted source leaves no sources;
|
|
189
|
+
* a named source records its claim for later `confirm`, without changing any trust store now. The person's own id
|
|
190
|
+
* and 'self' are refused (they mark observation): use `confirm` for something the person saw.
|
|
191
|
+
* It does not apply reputation to relationships; use `seedTie` to author a relationship.
|
|
192
|
+
*/
|
|
193
|
+
export function seedBelief(p, prop, spec) {
|
|
194
|
+
const at = spec.at ?? p.now;
|
|
195
|
+
if (!Number.isFinite(spec.credence))
|
|
196
|
+
throw new Error('human: belief credence must be finite');
|
|
197
|
+
if (!Number.isFinite(at))
|
|
198
|
+
throw new Error('human: belief time must be finite');
|
|
199
|
+
// The person's own id and 'self' mark direct observation (`observedDiscount`, `confirm`); authoring is not seeing.
|
|
200
|
+
if (spec.source === p.id || spec.source === 'self')
|
|
201
|
+
throw new Error('human: an authored belief cannot name the person as its source; use confirm for an observation');
|
|
202
|
+
const b = ensureBelief(p, prop, at);
|
|
203
|
+
const limit = BELIEF_DEFAULTS.maxLogOdds;
|
|
204
|
+
b.logOdds = clamp((spec.value ? 1 : -1) * logit(clamp01(spec.credence)), -limit, limit);
|
|
205
|
+
b.updatedAt = at;
|
|
206
|
+
b.sources = spec.source === undefined ? [] : [{ id: spec.source, value: spec.value }];
|
|
207
|
+
return b;
|
|
208
|
+
}
|
|
144
209
|
/** Testimony or inference: add reliability-weighted log-odds evidence for (or against) `prop`. */
|
|
145
210
|
export function believe(p, prop, value, confidence, sourceId, now) {
|
|
146
211
|
const d = BELIEF_DEFAULTS;
|
|
@@ -182,7 +247,13 @@ export function confirm(p, prop, truth, now) {
|
|
|
182
247
|
if (s.id === p.id || s.id === 'self')
|
|
183
248
|
continue;
|
|
184
249
|
const t = trustOf(p, s.id);
|
|
185
|
-
|
|
250
|
+
// An own data property even for ids such as `__proto__` (plain assignment would set the prototype).
|
|
251
|
+
Object.defineProperty(p.memory.sourceTrust, s.id, {
|
|
252
|
+
value: clamp01(s.value === truth ? t + d.trustGain * (1 - t) : t - d.trustLoss * t),
|
|
253
|
+
writable: true,
|
|
254
|
+
enumerable: true,
|
|
255
|
+
configurable: true,
|
|
256
|
+
});
|
|
186
257
|
if (s.value !== truth)
|
|
187
258
|
misled.push(s.id);
|
|
188
259
|
}
|
|
@@ -221,3 +292,136 @@ export function contested(p, prop) {
|
|
|
221
292
|
}
|
|
222
293
|
// Remembered advice (N9) is owned by `will/` (`standingAdvice`, fed from `Percept.advice`); review 2026-10-03
|
|
223
294
|
// removed a second, unused belief-based implementation here so the two could not drift apart.
|
|
295
|
+
// ---------------------------------------------------------------------------------------------
|
|
296
|
+
// Word and witness (2.10.0): provenance and contradiction.
|
|
297
|
+
// ---------------------------------------------------------------------------------------------
|
|
298
|
+
const validId = (x) => typeof x === 'string' && x.length > 0;
|
|
299
|
+
const validMinute = (x) => isNum(x) && Math.abs(x) <= MAX_MINUTE;
|
|
300
|
+
function cleanProvenance(x) {
|
|
301
|
+
if (!isObj(x) || !validId(x.origin) || !validId(x.firstFrom) || !validMinute(x.at))
|
|
302
|
+
return undefined;
|
|
303
|
+
if (x.lineage !== undefined && typeof x.lineage !== 'string')
|
|
304
|
+
return undefined;
|
|
305
|
+
const out = { origin: x.origin, firstFrom: x.firstFrom, at: x.at };
|
|
306
|
+
if (typeof x.lineage === 'string' && x.lineage.length <= 64)
|
|
307
|
+
out.lineage = x.lineage;
|
|
308
|
+
return out;
|
|
309
|
+
}
|
|
310
|
+
/** Record where a belief came from, if it has no provenance yet (first acquisition wins). @internal */
|
|
311
|
+
export function noteProvenance(p, claim, teller, at) {
|
|
312
|
+
if (claim.origin === undefined && claim.lineage === undefined)
|
|
313
|
+
return;
|
|
314
|
+
const b = findBelief(p, claim.prop);
|
|
315
|
+
if (!b || b.provenance !== undefined)
|
|
316
|
+
return;
|
|
317
|
+
const input = { origin: claim.origin ?? teller, firstFrom: teller, at };
|
|
318
|
+
if (claim.lineage !== undefined)
|
|
319
|
+
input.lineage = claim.lineage;
|
|
320
|
+
const meta = cleanProvenance(input);
|
|
321
|
+
if (meta !== undefined)
|
|
322
|
+
b.provenance = meta;
|
|
323
|
+
}
|
|
324
|
+
/** Where this person first got the belief on `prop`, or undefined. */
|
|
325
|
+
export function provenanceOf(p, prop) {
|
|
326
|
+
return findBelief(p, prop)?.provenance;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* The person learns that `sourceId` also gave the account `prop = value` elsewhere, against what that source told
|
|
330
|
+
* them. See the contradiction SCOPE.
|
|
331
|
+
*/
|
|
332
|
+
export function contradicted(p, ev) {
|
|
333
|
+
return applyContradiction(p, ev, ev.reporterId === undefined ? undefined : trustOf(p, ev.reporterId));
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* `contradicted` with the reporter's trust given, so that several reports delivered together share one trust basis
|
|
337
|
+
* (`perceive` reads it once per percept, before any report applies). @internal
|
|
338
|
+
*/
|
|
339
|
+
export function applyContradiction(p, ev, reporterTrust) {
|
|
340
|
+
const t = trustOf(p, ev.sourceId);
|
|
341
|
+
const refused = (reason) => ({
|
|
342
|
+
applied: false,
|
|
343
|
+
reason,
|
|
344
|
+
before: t,
|
|
345
|
+
after: t,
|
|
346
|
+
});
|
|
347
|
+
if (ev.sourceId === p.id || ev.sourceId === 'self')
|
|
348
|
+
return refused('self');
|
|
349
|
+
const weight = reporterTrust === undefined ? 1 : testimonyWeight(reporterTrust);
|
|
350
|
+
// One loss per (source, proposition), at the strongest evidence: a weaker earlier report leaves room for the rest.
|
|
351
|
+
const prior = p.memory.contradictions?.find((x) => x.sourceId === ev.sourceId && x.prop === ev.prop);
|
|
352
|
+
const priorWeight = prior === undefined ? 0 : (prior.weight ?? 1);
|
|
353
|
+
if (prior !== undefined && priorWeight >= weight)
|
|
354
|
+
return refused('already-noted');
|
|
355
|
+
const account = findBelief(p, ev.prop)?.sources.find((s) => s.id === ev.sourceId);
|
|
356
|
+
if (!account)
|
|
357
|
+
return refused('no-account');
|
|
358
|
+
if (account.value === ev.value)
|
|
359
|
+
return refused('same-account');
|
|
360
|
+
// A reporter at or below the trust floor carries no weight and must not use up the pair.
|
|
361
|
+
if (weight <= 0)
|
|
362
|
+
return refused('untrusted-reporter');
|
|
363
|
+
const at = ev.at ?? p.now;
|
|
364
|
+
if (!validMinute(at))
|
|
365
|
+
throw new Error('human: contradiction time must be a finite supported minute');
|
|
366
|
+
const loss = BELIEF_DEFAULTS.contradictionLoss;
|
|
367
|
+
// Multiplicative, so the total over a pair is `1 - loss * strongest weight` whatever the arrival order.
|
|
368
|
+
const after = seedSourceTrust(p, ev.sourceId, (t * (1 - loss * weight)) / (1 - loss * priorWeight));
|
|
369
|
+
if (prior !== undefined) {
|
|
370
|
+
if (weight >= 1)
|
|
371
|
+
delete prior.weight;
|
|
372
|
+
else
|
|
373
|
+
prior.weight = weight;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const noted = p.memory.contradictions ?? [];
|
|
377
|
+
const row = { sourceId: ev.sourceId, prop: ev.prop, at };
|
|
378
|
+
if (weight < 1)
|
|
379
|
+
row.weight = weight;
|
|
380
|
+
noted.push(row);
|
|
381
|
+
noted.sort((a, b) => a.at - b.at);
|
|
382
|
+
p.memory.contradictions = noted.slice(-BELIEF_DEFAULTS.maxContradictions);
|
|
383
|
+
}
|
|
384
|
+
return { applied: true, before: t, after };
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Restore (2.10.0): drop malformed provenance (lineage over 64 characters is dropped, not truncated) and bound and
|
|
388
|
+
* validate `contradictions`. A save the engine wrote is unchanged. @internal
|
|
389
|
+
*/
|
|
390
|
+
export function sanitizeBeliefMeta(memory) {
|
|
391
|
+
for (const b of memory.beliefs) {
|
|
392
|
+
if (!isObj(b) || b.provenance === undefined)
|
|
393
|
+
continue;
|
|
394
|
+
const meta = cleanProvenance(b.provenance);
|
|
395
|
+
if (meta === undefined)
|
|
396
|
+
delete b.provenance;
|
|
397
|
+
else
|
|
398
|
+
b.provenance = meta;
|
|
399
|
+
}
|
|
400
|
+
if (memory.contradictions === undefined)
|
|
401
|
+
return;
|
|
402
|
+
if (!Array.isArray(memory.contradictions)) {
|
|
403
|
+
delete memory.contradictions;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const clean = [];
|
|
407
|
+
const seen = new Map();
|
|
408
|
+
for (const x of memory.contradictions) {
|
|
409
|
+
if (!isObj(x) || typeof x.sourceId !== 'string' || typeof x.prop !== 'string' || !validMinute(x.at))
|
|
410
|
+
continue;
|
|
411
|
+
const props = seen.get(x.sourceId) ?? new Set();
|
|
412
|
+
if (props.has(x.prop))
|
|
413
|
+
continue;
|
|
414
|
+
props.add(x.prop);
|
|
415
|
+
seen.set(x.sourceId, props);
|
|
416
|
+
const row = { sourceId: x.sourceId, prop: x.prop, at: x.at };
|
|
417
|
+
// A malformed weight reads as 1 (fully applied): restore never reopens a pair to a further loss.
|
|
418
|
+
if (typeof x.weight === 'number' && Number.isFinite(x.weight) && x.weight > 0 && x.weight < 1)
|
|
419
|
+
row.weight = x.weight;
|
|
420
|
+
clean.push(row);
|
|
421
|
+
}
|
|
422
|
+
clean.sort((a, b) => a.at - b.at);
|
|
423
|
+
if (clean.length === 0)
|
|
424
|
+
delete memory.contradictions;
|
|
425
|
+
else
|
|
426
|
+
memory.contradictions = clean.slice(-BELIEF_DEFAULTS.maxContradictions);
|
|
427
|
+
}
|
|
@@ -225,7 +225,7 @@ export function socialContext(ctx) {
|
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
227
|
/** Same perceived-body effort estimate for actual offers and received successors. @internal */
|
|
228
|
-
|
|
228
|
+
function effortValue(p, aff, ctx) {
|
|
229
229
|
const K = COGNITION_DEFAULTS;
|
|
230
230
|
const per = ctx.body.perceived;
|
|
231
231
|
const effort = clamp01(aff.effort);
|
|
@@ -239,7 +239,7 @@ export function effortValue(p, aff, ctx) {
|
|
|
239
239
|
return -K.effortScale * effortCost;
|
|
240
240
|
}
|
|
241
241
|
/** Same material valuation for actual offers and received successor costs. @internal */
|
|
242
|
-
|
|
242
|
+
function materialValue(p, material, scarcity) {
|
|
243
243
|
const K = COGNITION_DEFAULTS;
|
|
244
244
|
const v = p.values;
|
|
245
245
|
const weight = (v.security + v.achievement + v.power) / 3;
|
|
@@ -100,9 +100,13 @@ export declare function recordDeed(p: Person, aff: Affordance, intention: string
|
|
|
100
100
|
* The person repents a breach: regret, stopping and resolve. When another person was wronged,
|
|
101
101
|
* restitution is also required, so the breach closes only after `recordRepair` for that victim.
|
|
102
102
|
* Returns whether the breach is now closed. This records the person's acts, not acceptance.
|
|
103
|
+
* The unused `_now` parameter is optional since 2.9.1 and is removed in 3.0.
|
|
103
104
|
*/
|
|
104
|
-
export declare function repent(p: Person, id: string, _now
|
|
105
|
-
/**
|
|
106
|
-
|
|
105
|
+
export declare function repent(p: Person, id: string, _now?: Minute): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Restitution/apology delivered to a wronged person (host-attested): closes their open breaches.
|
|
108
|
+
* The unused `_now` parameter is optional since 2.9.1 and is removed in 3.0.
|
|
109
|
+
*/
|
|
110
|
+
export declare function recordRepair(p: Person, victimId: string, _now?: Minute): number;
|
|
107
111
|
/** Felt weight of open breaches, saturating: 1 - Π(1 - weight). Input for guilt in affect. */
|
|
108
112
|
export declare function guiltLoad(p: Person): Unit;
|
|
@@ -351,6 +351,7 @@ export function recordDeed(p, aff, intention, now, completed, opts = {}) {
|
|
|
351
351
|
* The person repents a breach: regret, stopping and resolve. When another person was wronged,
|
|
352
352
|
* restitution is also required, so the breach closes only after `recordRepair` for that victim.
|
|
353
353
|
* Returns whether the breach is now closed. This records the person's acts, not acceptance.
|
|
354
|
+
* The unused `_now` parameter is optional since 2.9.1 and is removed in 3.0.
|
|
354
355
|
*/
|
|
355
356
|
export function repent(p, id, _now) {
|
|
356
357
|
const breach = p.conscience.breaches.find((b) => b.id === id);
|
|
@@ -361,7 +362,10 @@ export function repent(p, id, _now) {
|
|
|
361
362
|
breach.repaired = true;
|
|
362
363
|
return true;
|
|
363
364
|
}
|
|
364
|
-
/**
|
|
365
|
+
/**
|
|
366
|
+
* Restitution/apology delivered to a wronged person (host-attested): closes their open breaches.
|
|
367
|
+
* The unused `_now` parameter is optional since 2.9.1 and is removed in 3.0.
|
|
368
|
+
*/
|
|
365
369
|
export function recordRepair(p, victimId, _now) {
|
|
366
370
|
let count = 0;
|
|
367
371
|
for (const b of p.conscience.breaches) {
|
|
@@ -53,6 +53,8 @@ export interface ConverseContext {
|
|
|
53
53
|
magnitude?: Unit;
|
|
54
54
|
/** Character-trait vocabulary (defaults to `REPUTATION_TRAITS`). */
|
|
55
55
|
traits?: Record<string, TraitEffect>;
|
|
56
|
+
/** Carry belief origin and opaque lineage into told claims (off by default). */
|
|
57
|
+
provenance?: boolean;
|
|
56
58
|
}
|
|
57
59
|
/** Host-visible record of one claim. */
|
|
58
60
|
export interface ToldClaim {
|
|
@@ -69,6 +71,8 @@ export interface ToldClaim {
|
|
|
69
71
|
/** The person the claim is about, when it is a character claim. */
|
|
70
72
|
about?: PersonId;
|
|
71
73
|
score: number;
|
|
74
|
+
origin?: EntityId;
|
|
75
|
+
lineage?: string;
|
|
72
76
|
}
|
|
73
77
|
export interface AdviceGiven {
|
|
74
78
|
action: string;
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
* percept (it is in `claims`, not `told`). A claim this listener already heard from this speaker, in the same
|
|
30
30
|
* direction, is dropped before the speaker chooses, so it is not even a deed. The speaker keeps no memory of what was said to whom; the listener's
|
|
31
31
|
* belief stands in for it.
|
|
32
|
+
*
|
|
33
|
+
* SCOPE (Word and witness, 2.10.0): `provenance: true` carries each claim's first known origin and opaque
|
|
34
|
+
* lineage into testimony. Missing provenance names the speaker as origin. Metadata changes neither claim
|
|
35
|
+
* selection nor repetition rules; the host still owns the relay graph and disclosure. It does not establish
|
|
36
|
+
* that an origin is truthful, expose deceit to the listener, or infer who else heard a claim.
|
|
32
37
|
*/
|
|
33
38
|
import { clamp01, expit, round } from '../core/index.js';
|
|
34
39
|
import { isDeceased, isUnfavourableTrait, parseTraitProp, REPUTATION_TRAITS, relationshipWith, } from '../social/index.js';
|
|
@@ -191,6 +196,12 @@ export function converse(speaker, listener, ctx) {
|
|
|
191
196
|
.slice(0, Math.max(0, maxClaims));
|
|
192
197
|
const norms = new Map();
|
|
193
198
|
for (const c of chosen) {
|
|
199
|
+
if (ctx.provenance) {
|
|
200
|
+
const meta = speaker.memory.beliefs.find((b) => b.prop === c.prop)?.provenance;
|
|
201
|
+
c.origin = meta?.origin ?? speaker.id;
|
|
202
|
+
if (meta?.lineage !== undefined)
|
|
203
|
+
c.lineage = meta.lineage;
|
|
204
|
+
}
|
|
194
205
|
out.claims.push(c);
|
|
195
206
|
const pcNorms = [];
|
|
196
207
|
if (c.backbiting) {
|
|
@@ -220,6 +231,11 @@ export function converse(speaker, listener, ctx) {
|
|
|
220
231
|
? `${nameOf(speaker)} says ${c.about} is ${c.value ? '' : 'not '}${c.prop.split(':')[1] ?? ''}`
|
|
221
232
|
: `${nameOf(speaker)} says ${c.prop} is ${c.value ? 'so' : 'not so'}`,
|
|
222
233
|
};
|
|
234
|
+
const claim = pc.claims?.[0];
|
|
235
|
+
if (claim && c.origin !== undefined)
|
|
236
|
+
claim.origin = c.origin;
|
|
237
|
+
if (claim && c.lineage !== undefined)
|
|
238
|
+
claim.lineage = c.lineage;
|
|
223
239
|
if (c.about !== undefined) {
|
|
224
240
|
pc.targetId = c.about;
|
|
225
241
|
const parsed = parseTraitProp(c.prop, table);
|
|
@@ -260,6 +276,15 @@ export function converse(speaker, listener, ctx) {
|
|
|
260
276
|
claims: [{ prop: `advice:${a.action}`, value: true, confidence: round(a.cred) }],
|
|
261
277
|
summary: `${nameOf(speaker)} says I should ${a.action}`,
|
|
262
278
|
};
|
|
279
|
+
if (ctx.provenance) {
|
|
280
|
+
const meta = beliefs.find((b) => b.prop === `${prefix}${a.action}`)?.provenance;
|
|
281
|
+
const claim = percept.claims?.[0];
|
|
282
|
+
if (claim) {
|
|
283
|
+
claim.origin = meta?.origin ?? speaker.id;
|
|
284
|
+
if (meta?.lineage !== undefined)
|
|
285
|
+
claim.lineage = meta.lineage;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
263
288
|
if (ctx.placeId !== undefined)
|
|
264
289
|
percept.placeId = ctx.placeId;
|
|
265
290
|
const suggestion = { voiceId: speaker.id, action: a.action, strength: round(a.strength) };
|
package/dist/core/math.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare const clampSigned: (value: number) => number;
|
|
|
5
5
|
export declare const lerp: (a: number, b: number, t: number) => number;
|
|
6
6
|
export declare const sigmoid: (x: number) => number;
|
|
7
7
|
export declare const logit: (p: number) => number;
|
|
8
|
+
/** @deprecated since 2.9.1, removed in 3.0; use sigmoid */
|
|
8
9
|
export declare const expit: typeof sigmoid;
|
|
9
10
|
/** Exponential decay of `value` toward `target` over `dt` minutes with the given half-life. */
|
|
10
11
|
export declare function decay(value: number, dt: number, halfLife: number, target?: number): number;
|
package/dist/core/math.js
CHANGED
|
@@ -36,6 +36,7 @@ export const logit = (p) => {
|
|
|
36
36
|
const q = clamp(p, 1e-6, 1 - 1e-6);
|
|
37
37
|
return dlog(q / (1 - q));
|
|
38
38
|
};
|
|
39
|
+
/** @deprecated since 2.9.1, removed in 3.0; use sigmoid */
|
|
39
40
|
export const expit = sigmoid;
|
|
40
41
|
/** Exponential decay of `value` toward `target` over `dt` minutes with the given half-life. */
|
|
41
42
|
export function decay(value, dt, halfLife, target = 0) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Human Framework
|
|
2
|
-
export declare const FRAMEWORK_VERSION = "2.
|
|
1
|
+
/** Human Framework public surface. */
|
|
2
|
+
export declare const FRAMEWORK_VERSION = "2.10.0";
|
|
3
3
|
export type { CrisisEvent, PracticeKind } from './affect/index.ts';
|
|
4
4
|
export { AFFECT_DEFAULTS, actionTendencies, advanceAffect, appraise, breakAllows, breakBehaviour, breakHazard, CRISIS_DEFAULTS, checkCrisis, createAffect, easeBreak, emotionLevel, enableBreaks, feel, inBreak, readAffect, regulate, release as releaseEmotion, skipCrisis, strain, tendencyEmotions, } from './affect/index.ts';
|
|
5
5
|
export type { GoalTemplate, PrayerCalendar, PrayerSchedule, PrayerTimes, Retimer, } from './agenda/index.ts';
|
|
@@ -31,7 +31,7 @@ export * from './person.ts';
|
|
|
31
31
|
export * from './promptings/index.ts';
|
|
32
32
|
export type { ConsequenceEvidence } from './prospection/index.ts';
|
|
33
33
|
export { bodyForecastFor, bodyForecastTerm, consequenceEvidence, FORECAST_DEFAULTS, forecastLine, forecastThresholds, PROSPECTION_DEFAULTS, } from './prospection/index.ts';
|
|
34
|
-
export
|
|
34
|
+
export { fingerprint, restore, snapshot } from './restore.ts';
|
|
35
35
|
export * from './review/index.ts';
|
|
36
36
|
export * from './scenarios/index.ts';
|
|
37
37
|
export * from './sim/index.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Human Framework
|
|
2
|
-
export const FRAMEWORK_VERSION = '2.
|
|
1
|
+
/** Human Framework public surface. */
|
|
2
|
+
export const FRAMEWORK_VERSION = '2.10.0';
|
|
3
3
|
export { AFFECT_DEFAULTS, actionTendencies, advanceAffect, appraise, breakAllows, breakBehaviour, breakHazard, CRISIS_DEFAULTS, checkCrisis, createAffect, easeBreak, emotionLevel, enableBreaks, feel, inBreak, readAffect, regulate, release as releaseEmotion, skipCrisis, strain, tendencyEmotions, } from './affect/index.js';
|
|
4
4
|
// `agenda.release` collides with `affect.release`; the agenda one is re-exported under a clearer name.
|
|
5
5
|
export { AGENDA_DEFAULTS, abandonGoal, adoptGoal, advanceAgenda, agendaTerms, applyExemptions, CARE_DEFAULTS, calendarRetimer, careDuty, commitmentPressure, createAgenda, DEFAULT_PRAYER_TIMES, EID_PRAYER_IMPORTANCE, EXEMPTION_DEFAULTS, eidPrayer, eidWindow, fastWindow, iftarWindow, inMakruhTime, isUnderWay, MAKRUH_DEFAULTS, makruhWindows, missedExcuse, onFinished, owedMakeUps, PRAYER_IMPORTANCE, PURPOSE_DEFAULTS, prayerWindows, pressureReachedAt, promise, proposeGoals, RAMADAN_DEFAULTS, ramadanFast, ramadanMeals, release as releaseCommitment, retimeCommitments, revisePurposes, scheduleMakeUp, spanMeetsWindow, suhoorWindow, timesFor, violatesAbstention, } from './agenda/index.js';
|
|
@@ -27,7 +27,7 @@ export * from './partnering/index.js';
|
|
|
27
27
|
export * from './person.js';
|
|
28
28
|
export * from './promptings/index.js';
|
|
29
29
|
export { bodyForecastFor, bodyForecastTerm, consequenceEvidence, FORECAST_DEFAULTS, forecastLine, forecastThresholds, PROSPECTION_DEFAULTS, } from './prospection/index.js';
|
|
30
|
-
export
|
|
30
|
+
export { fingerprint, restore, snapshot } from './restore.js';
|
|
31
31
|
export * from './review/index.js';
|
|
32
32
|
export * from './scenarios/index.js';
|
|
33
33
|
export * from './sim/index.js';
|
package/dist/memory/memory.js
CHANGED
|
@@ -349,7 +349,10 @@ export function retell(teller, listener, when, knobs = {}) {
|
|
|
349
349
|
}
|
|
350
350
|
/** The same thing happening, whoever it happened to (kind, action, target, place). */
|
|
351
351
|
const sameStory = (g, e) => g.kind === e.kind && g.action === e.action && g.targetId === e.targetId && g.placeId === e.placeId;
|
|
352
|
-
const trustOfSource = (p, id) =>
|
|
352
|
+
const trustOfSource = (p, id) => {
|
|
353
|
+
const own = Object.hasOwn(p.memory.sourceTrust, id) ? p.memory.sourceTrust[id] : undefined;
|
|
354
|
+
return typeof own === 'number' ? own : 0.5;
|
|
355
|
+
};
|
|
353
356
|
const idNum = (id) => Number(id.slice(1)) || 0;
|
|
354
357
|
const byId = (a, b) => idNum(a.id) - idNum(b.id);
|
|
355
358
|
function recency(now, at) {
|
package/dist/migrate.js
CHANGED
|
@@ -8,7 +8,19 @@
|
|
|
8
8
|
* field of the optional surroundings slice (`ambient.now` → `ambient.percept`) and changes no behaviour (the optional `social.impressions` and `social.reserve`, like `retention`, are optional and start
|
|
9
9
|
* absent in a migrated save); `restore` then fills and sanitizes
|
|
10
10
|
* the slices as for any save. 2.0.0 to 2.1.0 adds optional conditional method state, absent
|
|
11
|
-
* until explicitly used, so existing hosts retain their previous behavior; that step stamps the version.
|
|
11
|
+
* until explicitly used, so existing hosts retain their previous behavior; that step stamps the version.
|
|
12
|
+
* 2.1.0 to 2.2.0 preserves optional method records and stamps the version; successful alternatives now
|
|
13
|
+
* retain independent support. 2.2.0 to 2.3.0 stamps the version; received consequences and temporal goals
|
|
14
|
+
* remain absent unless explicitly supplied. 2.3.0 to 2.4.0 stamps the version; promptings remain absent
|
|
15
|
+
* unless enabled. 2.4.0 to 2.5.0 stamps the version; the bodily forecast reads only offers that declare
|
|
16
|
+
* `followedBy`. 2.5.0 to 2.6.0 stamps the version; the fatigue store stays absent unless enabled. 2.6.0 to
|
|
17
|
+
* 2.7.0 stamps the version; the evening review stays absent unless enabled. 2.7.0 to 2.8.0 stamps the
|
|
18
|
+
* version; fullness stays absent unless enabled, and alongside partners and reconsideration are opt-in.
|
|
19
|
+
* 2.8.0 to 2.9.0 stamps the version; prompting cues and practice half-lives stay absent unless supplied,
|
|
20
|
+
* review terms may carry refs, and an outcome naming several commitments now keeps each rather than only
|
|
21
|
+
* the earliest-ending one. 2.9.0 to 2.10.0 stamps the version; belief provenance, noted contradictions and
|
|
22
|
+
* believed regard stay absent unless a host supplies them;
|
|
23
|
+
* `regard` becomes a reserved impression cue key. A migrated save continues under the current engine's rules: it restores and runs,
|
|
12
24
|
* but it does not reproduce what the old engine would have done next where the rules changed (1.4.0 to 1.5.0
|
|
13
25
|
* changed how standing advice is heard; 1.8.0 to 1.9.0 changed the omission rule). Saves older than 1.4.0 and unknown versions are refused with an error.
|
|
14
26
|
*
|
|
@@ -58,6 +70,11 @@ export const MIGRATIONS = {
|
|
|
58
70
|
note: 'the surroundings field `ambient.now` is renamed `ambient.percept`; per-person retention is optional and starts absent; behaviour unchanged',
|
|
59
71
|
apply: renameAmbient,
|
|
60
72
|
},
|
|
73
|
+
'2.9.0': {
|
|
74
|
+
to: '2.10.0',
|
|
75
|
+
note: 'belief provenance (Belief.provenance), noted contradictions (memory.contradictions) and the believed-regard impression cue are optional and start absent; existing hosts retain exact behavior',
|
|
76
|
+
apply: stamp,
|
|
77
|
+
},
|
|
61
78
|
'2.8.0': {
|
|
62
79
|
to: '2.9.0',
|
|
63
80
|
note: 'prompting responses may carry a cue and the slice a practice half-life (both optional, absent as before); review terms may carry a ref; an outcome naming two or more commitments in fulfills now keeps each of them, where 2.8.0 kept the earliest-ending one',
|