@lmzhen/dsh-evolution-feedback 0.3.27 → 0.3.28

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 CHANGED
@@ -21,4 +21,4 @@ Independent of request-prefix construction. This package does not alter the asse
21
21
  ## Known Limitations and Deferred Work
22
22
 
23
23
 
24
- - - Persists through the IO seam; quality propagation into skill usage requires the `skillUsage` service.
24
+ - Persists through the IO seam; quality propagation into skill usage requires the `skillUsage` service.
package/lib/index.js CHANGED
@@ -33,6 +33,12 @@ var EvolutionFeedback = class {
33
33
  eventsPath;
34
34
  io;
35
35
  warn;
36
+ /** V4-41 (F-324): the last note per target CONFIRMED on the event log. The
37
+ * in-memory `lastNote` is optimistic; a failed append must roll back to this,
38
+ * never to the in-memory `previousNote` (an earlier failed call can leave an
39
+ * unpersisted note there, and reverting to it resurrects a value the log
40
+ * never held). Seeded from the fold truth, updated on successful appends. */
41
+ durableNote = /* @__PURE__ */ new Map();
36
42
  constructor(io, home = evolutionRoot(), pathOverride, warn = () => {}) {
37
43
  this.path = pathOverride ?? join(home, "evolution", "feedback.json");
38
44
  this.eventsPath = eventsFile(home);
@@ -43,6 +49,10 @@ var EvolutionFeedback = class {
43
49
  attachIo(io) {
44
50
  this.io = io;
45
51
  }
52
+ /** Durable-note map key (V4-41): a target shares one record per mode. */
53
+ noteKey(mode, target) {
54
+ return `${mode}\u0000${target}`;
55
+ }
46
56
  mutate(task) {
47
57
  const run = this.chain.then(task, task);
48
58
  this.chain = run.then(() => void 0, () => void 0);
@@ -77,6 +87,8 @@ var EvolutionFeedback = class {
77
87
  ...this.state.sessions
78
88
  }
79
89
  };
90
+ for (const [target, record] of Object.entries(truth.skills)) this.durableNote.set(this.noteKey("skills", target), record.lastNote);
91
+ for (const [target, record] of Object.entries(truth.sessions)) this.durableNote.set(this.noteKey("sessions", target), record.lastNote);
80
92
  if (maxSeq > 0 && (!cache || cache.lastSeq < maxSeq)) try {
81
93
  await io.writeText(path, JSON.stringify({
82
94
  version: CACHE_VERSION,
@@ -93,7 +105,6 @@ var EvolutionFeedback = class {
93
105
  positive: 0,
94
106
  negative: 0
95
107
  };
96
- const previousNote = current.lastNote;
97
108
  current[rating] += 1;
98
109
  if (note !== void 0) current.lastNote = note;
99
110
  table[target] = current;
@@ -102,22 +113,28 @@ var EvolutionFeedback = class {
102
113
  if (!recordIo || !eventsPath) return;
103
114
  this.mutate(async () => {
104
115
  try {
105
- if (await appendEvolutionEvent(recordIo, eventsPath, {
116
+ const seq = await appendEvolutionEvent(recordIo, eventsPath, {
106
117
  type: "feedback",
107
118
  target,
108
119
  kind,
109
120
  rating,
110
121
  note
111
- }) % CACHE_SNAP_EVERY === 0) await this.writeCacheNow();
122
+ });
123
+ if (note !== void 0) this.durableNote.set(this.noteKey(mode, target), note);
124
+ if (seq % CACHE_SNAP_EVERY === 0) await this.writeCacheNow();
112
125
  } catch (error) {
113
126
  const rollback = table[target];
114
127
  if (rollback) {
115
128
  rollback[rating] -= 1;
116
129
  if (note !== void 0) {
117
- if (rollback.lastNote === note) if (previousNote === void 0) delete rollback.lastNote;
118
- else rollback.lastNote = previousNote;
130
+ if (rollback.lastNote === note) {
131
+ const durable = this.durableNote.get(this.noteKey(mode, target));
132
+ if (durable === void 0) delete rollback.lastNote;
133
+ else rollback.lastNote = durable;
134
+ }
119
135
  }
120
136
  }
137
+ this.warn(`evolution-feedback: failed to append feedback event for ${kind} "${target}": ${error instanceof Error ? error.message : String(error)}`);
121
138
  }
122
139
  });
123
140
  }
@@ -37,9 +37,17 @@ export declare class EvolutionFeedback {
37
37
  private readonly eventsPath?;
38
38
  private io;
39
39
  private warn;
40
+ /** V4-41 (F-324): the last note per target CONFIRMED on the event log. The
41
+ * in-memory `lastNote` is optimistic; a failed append must roll back to this,
42
+ * never to the in-memory `previousNote` (an earlier failed call can leave an
43
+ * unpersisted note there, and reverting to it resurrects a value the log
44
+ * never held). Seeded from the fold truth, updated on successful appends. */
45
+ private readonly durableNote;
40
46
  constructor(io?: IoLike, home?: string, pathOverride?: string, warn?: (message: string) => void);
41
47
  /** Bind the evolution IO backend after construction (S6.4 deferred binding). */
42
48
  attachIo(io: IoLike): void;
49
+ /** Durable-note map key (V4-41): a target shares one record per mode. */
50
+ private noteKey;
43
51
  private mutate;
44
52
  restore(io: IoLike): Promise<void>;
45
53
  record(target: string, rating: 'positive' | 'negative', note?: string, kind?: 'skill' | 'session'): void;
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.27",
4
+ "version": "0.3.28",
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.27"
34
+ "@lmzhen/dsh-evolution-core": "^0.3.28"
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.27",
40
- "@lmzhen/dsh-skill-usage": "^0.3.27"
39
+ "@lmzhen/dsh-evolution-io": "^0.3.28",
40
+ "@lmzhen/dsh-skill-usage": "^0.3.28"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
- "@lmzhen/dsh-evolution-io": "^0.3.27",
45
- "@lmzhen/dsh-evolution-io-node": "^0.3.27",
46
- "@lmzhen/dsh-skill-usage": "^0.3.27"
44
+ "@lmzhen/dsh-evolution-io": "^0.3.28",
45
+ "@lmzhen/dsh-evolution-io-node": "^0.3.28",
46
+ "@lmzhen/dsh-skill-usage": "^0.3.28"
47
47
  }
48
48
  }