@lmzhen/dsh-evolution-feedback 0.3.62 → 0.3.64

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
@@ -22,3 +22,4 @@ Independent of request-prefix construction. This package does not alter the asse
22
22
 
23
23
 
24
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.
package/lib/index.js CHANGED
@@ -6,8 +6,15 @@ import { join } from "node:path";
6
6
  * Feedback-to-quality scoring for self-evolution.
7
7
  *
8
8
  * Feedback is durable through `ctx.evolutionIo` (when mounted) and skill
9
- * feedback feeds `quality_score` / `quality_warn` on the usage record, so
10
- * curator decisions can consume it deterministically.
9
+ * feedback feeds the FEEDBACK-OWNED `feedback_score` / `feedback_warn` pair on
10
+ * the usage record. P1-1 (v15): this package used to write
11
+ * `quality_score`/`quality_warn` — but the curator's six-factor `scoreTree`
12
+ * overwrote those fields on every run BEFORE the lifecycle engine read them,
13
+ * so the advertised "curator decisions consume feedback deterministically"
14
+ * channel was dead. The lifecycle engine and the scope view now read the
15
+ * union `quality_warn || feedback_warn`, and the curator never writes the
16
+ * feedback pair (field-ownership contract on `UsageRecord` in
17
+ * evolution-core/usage.ts).
11
18
  *
12
19
  * Persistence (rc.68): the EVENTS LOG (`evolution/events.json`, via
13
20
  * `evolution-core/evolution-events.ts`) is the single source of truth —
@@ -123,6 +130,18 @@ var EvolutionFeedback = class EvolutionFeedback {
123
130
  } catch {}
124
131
  });
125
132
  }
133
+ /** External-producer contract (审计 B-4, v18): nothing inside the family
134
+ * calls `record` — the upstream `/feedback` command only appends a
135
+ * `feedback/record` session event carrying free text, which cannot be mapped
136
+ * to a (target, rating) pair without inventing semantics. A host that wants
137
+ * feedback-driven curation wires its own command/event to this method; the
138
+ * curator's union read (`feedback_warn`) then shortens the stale window.
139
+ * `feedback.spec.ts` pins that channel end to end.
140
+ * @param target - skill name or session id the rating belongs to.
141
+ * @param rating - `positive` or `negative`; other values are refused.
142
+ * @param note - optional free-text note carried into the durable event.
143
+ * @param kind - `skill` (default `session`) selects the score table.
144
+ */
126
145
  record(target, rating, note, kind = "session") {
127
146
  const mode = kind === "skill" ? "skills" : "sessions";
128
147
  const table = this.state[mode];
@@ -187,9 +206,14 @@ var EvolutionFeedback = class EvolutionFeedback {
187
206
  return (record.positive - record.negative) / total;
188
207
  }
189
208
  snapshot() {
209
+ const copyRecords = (table) => {
210
+ const out = {};
211
+ for (const [key, record] of Object.entries(table)) out[key] = { ...record };
212
+ return out;
213
+ };
190
214
  return {
191
- skills: { ...this.state.skills },
192
- sessions: { ...this.state.sessions }
215
+ skills: copyRecords(this.state.skills),
216
+ sessions: copyRecords(this.state.sessions)
193
217
  };
194
218
  }
195
219
  /** Await the pending record-task chain (unload safety; rc.66). */
@@ -360,6 +384,10 @@ function foldWithDelta(cache, events, warn = () => {}) {
360
384
  }
361
385
  function applyFeedbackEvent(state, event, warn = () => {}) {
362
386
  if (event.type !== "feedback") return;
387
+ if (event.kind !== "skill" && event.kind !== "session") {
388
+ warn(`evolution-feedback: skipping feedback event with invalid kind: ${String(event.kind)}`);
389
+ return;
390
+ }
363
391
  if (event.rating !== "positive" && event.rating !== "negative") {
364
392
  warn(`evolution-feedback: skipping feedback event with invalid rating: ${String(event.rating)}`);
365
393
  return;
@@ -458,7 +486,7 @@ function apply(ctx, rawConfig = {}) {
458
486
  if (kind !== "skill") return;
459
487
  const score = feedback.score(target, "skill");
460
488
  const warn = score < qualityWarnThreshold;
461
- skillUsage.setQuality(target, score, warn).catch((error) => {
489
+ skillUsage.setFeedbackQuality(target, score, warn).catch((error) => {
462
490
  skillCtx.logger.warn(error);
463
491
  });
464
492
  };
@@ -2,8 +2,15 @@
2
2
  * Feedback-to-quality scoring for self-evolution.
3
3
  *
4
4
  * Feedback is durable through `ctx.evolutionIo` (when mounted) and skill
5
- * feedback feeds `quality_score` / `quality_warn` on the usage record, so
6
- * curator decisions can consume it deterministically.
5
+ * feedback feeds the FEEDBACK-OWNED `feedback_score` / `feedback_warn` pair on
6
+ * the usage record. P1-1 (v15): this package used to write
7
+ * `quality_score`/`quality_warn` — but the curator's six-factor `scoreTree`
8
+ * overwrote those fields on every run BEFORE the lifecycle engine read them,
9
+ * so the advertised "curator decisions consume feedback deterministically"
10
+ * channel was dead. The lifecycle engine and the scope view now read the
11
+ * union `quality_warn || feedback_warn`, and the curator never writes the
12
+ * feedback pair (field-ownership contract on `UsageRecord` in
13
+ * evolution-core/usage.ts).
7
14
  *
8
15
  * Persistence (rc.68): the EVENTS LOG (`evolution/events.json`, via
9
16
  * `evolution-core/evolution-events.ts`) is the single source of truth —
@@ -63,6 +70,18 @@ export declare class EvolutionFeedback {
63
70
  private noteKey;
64
71
  private mutate;
65
72
  restore(io: IoLike): Promise<void>;
73
+ /** External-producer contract (审计 B-4, v18): nothing inside the family
74
+ * calls `record` — the upstream `/feedback` command only appends a
75
+ * `feedback/record` session event carrying free text, which cannot be mapped
76
+ * to a (target, rating) pair without inventing semantics. A host that wants
77
+ * feedback-driven curation wires its own command/event to this method; the
78
+ * curator's union read (`feedback_warn`) then shortens the stale window.
79
+ * `feedback.spec.ts` pins that channel end to end.
80
+ * @param target - skill name or session id the rating belongs to.
81
+ * @param rating - `positive` or `negative`; other values are refused.
82
+ * @param note - optional free-text note carried into the durable event.
83
+ * @param kind - `skill` (default `session`) selects the score table.
84
+ */
66
85
  record(target: string, rating: 'positive' | 'negative', note?: string, kind?: 'skill' | 'session'): void;
67
86
  score(target: string, kind?: 'skill' | 'session'): number;
68
87
  snapshot(): FeedbackState;
@@ -86,7 +105,9 @@ export declare class EvolutionFeedback {
86
105
  export declare function migrateFeedbackEvents(io: IoLike, eventsPath: string, aggregate: FeedbackState): Promise<void>;
87
106
  export declare const name = "evolution-feedback";
88
107
  export interface Config {
89
- /** Score below which curator receives quality_warn for a skill. */
108
+ /** Score below which the FEEDBACK pair flips to warned (P1-1, v15: written
109
+ * to `feedback_score`/`feedback_warn`; the lifecycle engine reads the union
110
+ * with the curator-owned `quality_warn`). */
90
111
  qualityWarnThreshold?: number;
91
112
  /** Explicit boot-cache file path; empty derives $DSH_HOME/evolution/feedback.json.
92
113
  * The event log always stays at $DSH_HOME/evolution/events.json (derived from
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.62",
4
+ "version": "0.3.64",
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.62"
34
+ "@lmzhen/dsh-evolution-core": "^0.3.64"
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.62",
40
- "@lmzhen/dsh-skill-usage": "^0.3.62"
39
+ "@lmzhen/dsh-evolution-io": "^0.3.64",
40
+ "@lmzhen/dsh-skill-usage": "^0.3.64"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
- "@lmzhen/dsh-evolution-io": "^0.3.62",
45
- "@lmzhen/dsh-evolution-io-node": "^0.3.62",
46
- "@lmzhen/dsh-skill-usage": "^0.3.62"
44
+ "@lmzhen/dsh-evolution-io": "^0.3.64",
45
+ "@lmzhen/dsh-evolution-io-node": "^0.3.64",
46
+ "@lmzhen/dsh-skill-usage": "^0.3.64"
47
47
  }
48
48
  }