@lmzhen/dsh-evolution-feedback 0.3.67 → 0.3.69

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/lib/index.js CHANGED
@@ -48,11 +48,16 @@ var EvolutionFeedback = class EvolutionFeedback {
48
48
  durableNote = /* @__PURE__ */ new Map();
49
49
  /** P2-32 (v11): process-level bound — every feedbacked session would
50
50
  * otherwise keep one entry for the whole process lifetime (a name + note
51
- * string per session); cap both maps and drop the oldest on overflow. */
51
+ * string per session); cap this map and drop the earliest-INSERTED entry on
52
+ * overflow (Map iteration order is insertion order, and re-setting an
53
+ * existing key does not refresh its position, so the eviction is FIFO rather
54
+ * than least-recently-used). `warnedMessages` carries the same bound through
55
+ * `WARNED_CAP` below. */
52
56
  static NOTE_CAP = 512;
53
57
  /** V5-32 (0.3.31): fire-and-forget append failures are warn-once per unique
54
58
  * message — a persistent refusal (e.g. a future-version log) must not spam
55
- * the log on every user feedback entry (family posture: process-level once). */
59
+ * the log on every user feedback entry (family posture: process-level once).
60
+ * Bounded like `durableNote`, with the same FIFO eviction. */
56
61
  warnedMessages = /* @__PURE__ */ new Set();
57
62
  WARNED_CAP = 512;
58
63
  /** V5-29 (0.3.31): invoked after a FAILED append rolled back, so a caller
@@ -142,6 +147,18 @@ var EvolutionFeedback = class EvolutionFeedback {
142
147
  * @param note - optional free-text note carried into the durable event.
143
148
  * @param kind - `skill` (default `session`) selects the score table.
144
149
  */
150
+ /**
151
+ * v30 FB-01: refold the shared event log into the in-process aggregate.
152
+ * The aggregate only folds at mount, so a long-lived process computed the
153
+ * ABSOLUTE feedback pair from a stale aggregate and overwrote the decision
154
+ * relevant `feedback_warn` another process had recorded. The log is the
155
+ * truth — re-reading it before each quality push shrinks the staleness
156
+ * window to the refold-vs-append race (near-zero, serialized by mutate).
157
+ */
158
+ async refold() {
159
+ if (!this.io) return;
160
+ await this.restore(this.io);
161
+ }
145
162
  record(target, rating, note, kind = "session") {
146
163
  const mode = kind === "skill" ? "skills" : "sessions";
147
164
  const table = this.state[mode];
@@ -505,9 +522,11 @@ function apply(ctx, rawConfig = {}) {
505
522
  const skillUsage = skillCtx.skillUsage;
506
523
  const pushQuality = (target, kind) => {
507
524
  if (kind !== "skill") return;
508
- const score = feedback.score(target, "skill");
509
- const warn = score < qualityWarnThreshold;
510
- skillUsage.setFeedbackQuality(target, score, warn).catch((error) => {
525
+ feedback.refold().then(() => {
526
+ const score = feedback.score(target, "skill");
527
+ const warn = score < qualityWarnThreshold;
528
+ return skillUsage.setFeedbackQuality(target, score, warn);
529
+ }).catch((error) => {
511
530
  skillCtx.logger.warn(error);
512
531
  });
513
532
  };
@@ -52,11 +52,16 @@ export declare class EvolutionFeedback {
52
52
  private readonly durableNote;
53
53
  /** P2-32 (v11): process-level bound — every feedbacked session would
54
54
  * otherwise keep one entry for the whole process lifetime (a name + note
55
- * string per session); cap both maps and drop the oldest on overflow. */
55
+ * string per session); cap this map and drop the earliest-INSERTED entry on
56
+ * overflow (Map iteration order is insertion order, and re-setting an
57
+ * existing key does not refresh its position, so the eviction is FIFO rather
58
+ * than least-recently-used). `warnedMessages` carries the same bound through
59
+ * `WARNED_CAP` below. */
56
60
  private static readonly NOTE_CAP;
57
61
  /** V5-32 (0.3.31): fire-and-forget append failures are warn-once per unique
58
62
  * message — a persistent refusal (e.g. a future-version log) must not spam
59
- * the log on every user feedback entry (family posture: process-level once). */
63
+ * the log on every user feedback entry (family posture: process-level once).
64
+ * Bounded like `durableNote`, with the same FIFO eviction. */
60
65
  private readonly warnedMessages;
61
66
  private readonly WARNED_CAP;
62
67
  /** V5-29 (0.3.31): invoked after a FAILED append rolled back, so a caller
@@ -82,6 +87,15 @@ export declare class EvolutionFeedback {
82
87
  * @param note - optional free-text note carried into the durable event.
83
88
  * @param kind - `skill` (default `session`) selects the score table.
84
89
  */
90
+ /**
91
+ * v30 FB-01: refold the shared event log into the in-process aggregate.
92
+ * The aggregate only folds at mount, so a long-lived process computed the
93
+ * ABSOLUTE feedback pair from a stale aggregate and overwrote the decision
94
+ * relevant `feedback_warn` another process had recorded. The log is the
95
+ * truth — re-reading it before each quality push shrinks the staleness
96
+ * window to the refold-vs-append race (near-zero, serialized by mutate).
97
+ */
98
+ refold(): Promise<void>;
85
99
  record(target: string, rating: 'positive' | 'negative', note?: string, kind?: 'skill' | 'session'): void;
86
100
  score(target: string, kind?: 'skill' | 'session'): number;
87
101
  snapshot(): FeedbackState;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-feedback",
3
3
  "description": "Feedback-to-quality scoring for self-evolution (community build)",
4
- "version": "0.3.67",
4
+ "version": "0.3.69",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,18 +31,18 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-core": "^0.3.67"
34
+ "@lmzhen/dsh-evolution-core": "^0.3.69"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
38
38
  "@deepseek-ai/cordis": "^4.0.1",
39
- "@lmzhen/dsh-evolution-io": "^0.3.67",
40
- "@lmzhen/dsh-skill-usage": "^0.3.67"
39
+ "@lmzhen/dsh-evolution-io": "^0.3.69",
40
+ "@lmzhen/dsh-skill-usage": "^0.3.69"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
- "@lmzhen/dsh-evolution-io": "^0.3.67",
45
- "@lmzhen/dsh-evolution-io-node": "^0.3.67",
46
- "@lmzhen/dsh-skill-usage": "^0.3.67"
44
+ "@lmzhen/dsh-evolution-io": "^0.3.69",
45
+ "@lmzhen/dsh-evolution-io-node": "^0.3.69",
46
+ "@lmzhen/dsh-skill-usage": "^0.3.69"
47
47
  }
48
48
  }