@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 +17 -17
- package/lib/index.js +41 -2
- package/lib/types/index.d.ts +18 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @lmzhen/dsh-evolution-feedback
|
|
2
2
|
|
|
3
|
-
Feedback-to-quality scoring
|
|
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
|
|
6
|
+
## Model surface
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
12
|
+
## Configuration
|
|
10
13
|
|
|
11
|
-
|
|
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
|
-
|
|
17
|
+
## Known limitations
|
|
14
18
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
171
|
+
...pickPending("skills")
|
|
140
172
|
},
|
|
141
173
|
sessions: {
|
|
142
174
|
...truth.sessions,
|
|
143
|
-
...
|
|
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;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
35
|
-
"@lmzhen/dsh-skill-usage": "^0.
|
|
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.
|
|
39
|
-
"@lmzhen/dsh-evolution-io-node": "^0.
|
|
40
|
-
"@lmzhen/dsh-skill-usage": "^0.
|
|
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
|
}
|