@lmzhen/dsh-evolution-feedback 0.3.82 → 0.4.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 CHANGED
@@ -1,27 +1,27 @@
1
- # @deepseek-ai/dsh-evolution-feedback
1
+ # @lmzhen/dsh-evolution-feedback
2
2
 
3
- Feedback-to-quality scoring for self-evolution
3
+ Feedback-to-quality scoring: durable through `ctx.evolutionIo`; skill feedback feeds the
4
+ FEEDBACK-OWNED `feedback_score`/`feedback_warn` pair.
4
5
 
5
- ## Model Experience
6
+ ## Model surface
6
7
 
7
- ### Indirect model surface
8
+ - **Model-visible:** nothing of its own: the usage-record readers own it.
9
+ - **Prompt prefix / KV cache:** unchanged by this package: family-level rules single-sourced in `packages/README.md` §"Model-visible prompt prefix and the KV cache".
10
+ - **Mount it?** yes — the `evolution-feedback` row, `evolution-host`/`evolution-all`/`evolution-preset`.
8
11
 
9
- #### What the model sees
12
+ ## Configuration
10
13
 
11
- `@deepseek-ai/dsh-evolution-feedback` registers no direct prompt or tool schema itself. Model-visible effects are owned by the packages that consume this service.
14
+ - `qualityWarnThreshold` (default `-0.25`): score below which the pair flips to warned.
15
+ - `path`: boot-cache path; `''` means `$DSH_HOME/evolution/feedback.json` (the event log is not affected).
12
16
 
13
- #### Token effect
17
+ ## Known limitations
14
18
 
15
- Zero direct token effect from this package; consumers add any model-visible tokens.
16
-
17
- #### KV Cache effect
18
-
19
- Independent of request-prefix construction. This package does not alter the assembled prompt or tool list.
20
-
21
- ## Known Limitations and Deferred Work
19
+ - Lifecycle and scope views read `quality_warn || feedback_warn`, so negative feedback shortens the stale window even though the curator recomputes `quality_warn`.
22
20
 
21
+ **Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
23
22
 
24
- - Persists through the IO seam; quality propagation into skill usage requires the `skillUsage` service.
25
- - P1-1 (v15): feedback writes the FEEDBACK-OWNED `feedback_score`/`feedback_warn` usage fields. The lifecycle engine and the scope view read the union `quality_warn || feedback_warn`, so a negative feedback shortens the stale window even though the curator's six-factor run always recomputes `quality_warn` itself.
23
+ ## Notes and history
26
24
 
27
- **Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
25
+ - Persists through the IO seam; quality propagation into skill usage requires BOTH the `skillUsage` service and a mounted IO backend: with no `evolutionIo` the push returns before touching the persistent usage sidecar (S4.6), so an optimistic in-memory score never lands there unconfirmed.
26
+ - The in-memory-wins window of a log refold is the IN-FLIGHT append window only, counted PER TARGET (two appends for one target in flight at once both stay protected, and the no-io path never enters it): a settled target folds from the log truth, so another process sharing `DSH_HOME` is not overwritten by this process's stale record (S1.4).
27
+ - P1-1 (v15): feedback writes the FEEDBACK-OWNED `feedback_score`/`feedback_warn` usage fields.
package/lib/index.js CHANGED
@@ -57,6 +57,21 @@ var EvolutionFeedback = class EvolutionFeedback {
57
57
  * unpersisted note there, and reverting to it resurrects a value the log
58
58
  * never held). Seeded from the fold truth, updated on successful appends. */
59
59
  durableNote = /* @__PURE__ */ new Map();
60
+ /** PLAN S1.4 (2026-09-16): targets with a feedback append still IN FLIGHT,
61
+ * split by table, as a COUNT per target. record() increments before queueing
62
+ * the append and the append task decrements when it settles (landed or rolled
63
+ * back, finally), dropping the entry only at ZERO — the count covers exactly
64
+ * the optimistic window rc.66 meant to protect, including two appends for the
65
+ * same target in flight at once (review C-P2-1: a per-target boolean marker
66
+ * was cleared by the first settle, so a merge between the two appends folded
67
+ * the second append's increment away). restore() lets memory win ONLY for these targets — a settled
68
+ * target folds from the log truth, so another process's feedback for the
69
+ * same target (audit P1-3) is never overwritten by this process's stale
70
+ * record. */
71
+ pendingAppends = {
72
+ skills: /* @__PURE__ */ new Map(),
73
+ sessions: /* @__PURE__ */ new Map()
74
+ };
60
75
  /** P2-32 (v11): process-level bound — every feedbacked session would
61
76
  * otherwise keep one entry for the whole process lifetime (a name + note
62
77
  * string per session); cap this map and drop the earliest-INSERTED entry on
@@ -85,6 +100,14 @@ var EvolutionFeedback = class EvolutionFeedback {
85
100
  attachIo(io) {
86
101
  this.io = io;
87
102
  }
103
+ /** PLAN S4.6 (2026-09-16): whether a durable backend is attached — the
104
+ * plugin's quality push (`apply`) consults this before writing the
105
+ * feedback pair into the skill-usage sidecar. Same no-io posture as
106
+ * `record`/`refold`: without `ctx.evolutionIo` (when mounted) nothing may
107
+ * turn the optimistic in-memory aggregate into a durable side effect. */
108
+ get durable() {
109
+ return this.io !== void 0 && !!this.eventsPath;
110
+ }
88
111
  /** V5-32 posture applied to the read side (C-events-dispatch-1, v43): an
89
112
  * event a repeated read keeps reporting must not warn on each read —
90
113
  * `refold()` calls `restore()` before every quality push. Shares the bounded
@@ -133,14 +156,23 @@ var EvolutionFeedback = class EvolutionFeedback {
133
156
  const floor = events[0]?.seq ?? 0;
134
157
  const usableCache = cache && cache.lastSeq >= floor - 1 ? cache : null;
135
158
  const truth = usableCache ? foldWithDelta(usableCache, events, this.warn) : foldFeedbackState(events, this.warn);
159
+ const pickPending = (mode) => {
160
+ const picked = {};
161
+ for (const [target, inFlight] of this.pendingAppends[mode]) {
162
+ if (inFlight <= 0) continue;
163
+ const record = this.state[mode][target];
164
+ if (record) picked[target] = record;
165
+ }
166
+ return picked;
167
+ };
136
168
  this.state = {
137
169
  skills: {
138
170
  ...truth.skills,
139
- ...this.state.skills
171
+ ...pickPending("skills")
140
172
  },
141
173
  sessions: {
142
174
  ...truth.sessions,
143
- ...this.state.sessions
175
+ ...pickPending("sessions")
144
176
  }
145
177
  };
146
178
  const skillEntries = Object.entries(truth.skills);
@@ -204,6 +236,8 @@ var EvolutionFeedback = class EvolutionFeedback {
204
236
  const recordIo = this.io;
205
237
  const eventsPath = this.eventsPath;
206
238
  if (!recordIo || !eventsPath) return;
239
+ const pending = this.pendingAppends[mode];
240
+ pending.set(target, (pending.get(target) ?? 0) + 1);
207
241
  this.mutate(async () => {
208
242
  try {
209
243
  const seq = await appendEvolutionEvent(recordIo, eventsPath, {
@@ -244,6 +278,10 @@ var EvolutionFeedback = class EvolutionFeedback {
244
278
  this.warn(message);
245
279
  }
246
280
  if (rollback) this.onRollback?.(target, kind);
281
+ } finally {
282
+ const remaining = (pending.get(target) ?? 1) - 1;
283
+ if (remaining > 0) pending.set(target, remaining);
284
+ else pending.delete(target);
247
285
  }
248
286
  });
249
287
  }
@@ -617,6 +655,7 @@ function apply(ctx, rawConfig = {}) {
617
655
  const skillUsage = skillCtx.skillUsage;
618
656
  const pushQuality = (target, kind) => {
619
657
  if (kind !== "skill") return;
658
+ if (!feedback.durable) return;
620
659
  feedback.refold().then(() => {
621
660
  const score = feedback.score(target, "skill");
622
661
  const warn = score < qualityWarnThreshold;
@@ -50,6 +50,18 @@ export declare class EvolutionFeedback {
50
50
  * unpersisted note there, and reverting to it resurrects a value the log
51
51
  * never held). Seeded from the fold truth, updated on successful appends. */
52
52
  private readonly durableNote;
53
+ /** PLAN S1.4 (2026-09-16): targets with a feedback append still IN FLIGHT,
54
+ * split by table, as a COUNT per target. record() increments before queueing
55
+ * the append and the append task decrements when it settles (landed or rolled
56
+ * back, finally), dropping the entry only at ZERO — the count covers exactly
57
+ * the optimistic window rc.66 meant to protect, including two appends for the
58
+ * same target in flight at once (review C-P2-1: a per-target boolean marker
59
+ * was cleared by the first settle, so a merge between the two appends folded
60
+ * the second append's increment away). restore() lets memory win ONLY for these targets — a settled
61
+ * target folds from the log truth, so another process's feedback for the
62
+ * same target (audit P1-3) is never overwritten by this process's stale
63
+ * record. */
64
+ private readonly pendingAppends;
53
65
  /** P2-32 (v11): process-level bound — every feedbacked session would
54
66
  * otherwise keep one entry for the whole process lifetime (a name + note
55
67
  * string per session); cap this map and drop the earliest-INSERTED entry on
@@ -71,6 +83,12 @@ export declare class EvolutionFeedback {
71
83
  constructor(io?: IoLike, home?: string, pathOverride?: string, warn?: (message: string) => void);
72
84
  /** Bind the evolution IO backend after construction (S6.4 deferred binding). */
73
85
  attachIo(io: IoLike): void;
86
+ /** PLAN S4.6 (2026-09-16): whether a durable backend is attached — the
87
+ * plugin's quality push (`apply`) consults this before writing the
88
+ * feedback pair into the skill-usage sidecar. Same no-io posture as
89
+ * `record`/`refold`: without `ctx.evolutionIo` (when mounted) nothing may
90
+ * turn the optimistic in-memory aggregate into a durable side effect. */
91
+ get durable(): boolean;
74
92
  /** V5-32 posture applied to the read side (C-events-dispatch-1, v43): an
75
93
  * event a repeated read keeps reporting must not warn on each read —
76
94
  * `refold()` calls `restore()` before every quality push. Shares the bounded
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.82",
4
+ "version": "0.4.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,16 +27,16 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.1",
30
- "@lmzhen/dsh-evolution-core": "^0.3.82"
30
+ "@lmzhen/dsh-evolution-core": "^0.4.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@deepseek-ai/cordis": "^4.0.1",
34
- "@lmzhen/dsh-evolution-io": "^0.3.82",
35
- "@lmzhen/dsh-skill-usage": "^0.3.82"
34
+ "@lmzhen/dsh-evolution-io": "^0.4.0",
35
+ "@lmzhen/dsh-skill-usage": "^0.4.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@lmzhen/dsh-evolution-io": "^0.3.82",
39
- "@lmzhen/dsh-evolution-io-node": "^0.3.82",
40
- "@lmzhen/dsh-skill-usage": "^0.3.82"
38
+ "@lmzhen/dsh-evolution-io": "^0.4.0",
39
+ "@lmzhen/dsh-evolution-io-node": "^0.4.0",
40
+ "@lmzhen/dsh-skill-usage": "^0.4.0"
41
41
  }
42
42
  }