@lmzhen/dsh-evolution-plan-validator 0.3.61 → 0.3.63

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.
Files changed (2) hide show
  1. package/lib/index.js +29 -1
  2. package/package.json +2 -2
package/lib/index.js CHANGED
@@ -144,6 +144,13 @@ function validateEvolutionPlan(plan, context) {
144
144
  };
145
145
  }
146
146
  function validateMemoryOp(op, context, index) {
147
+ const badField = malformedStringField(op, [
148
+ "facts",
149
+ "content",
150
+ "old_text",
151
+ "target"
152
+ ]);
153
+ if (badField) return `memory op ${index}: field ${badField} must be a string`;
147
154
  if (!hasValidEvidence(op.evidence, context.sessionSeq)) return `memory op ${index}: evidence is required and must reference a valid session seq`;
148
155
  for (const key of FORBIDDEN_KEYS) if (key in op) return `memory op ${index}: forbidden field ${key}`;
149
156
  if (op.target !== "memory" && op.target !== "user") return `memory op ${index}: target must be memory or user`;
@@ -156,7 +163,28 @@ function validateMemoryOp(op, context, index) {
156
163
  if (text.length > budget) return `memory op ${index}: content exceeds ${op.target === "user" ? "user" : "memory"} budget`;
157
164
  return null;
158
165
  }
166
+ /** P2-1 (v15): the string-typed fields the executors dereference with
167
+ * `.trim()`/`.length`. `target` is included for memory ops because the
168
+ * engine compares it against literals. */
169
+ function malformedStringField(op, fields) {
170
+ const record = op;
171
+ for (const field of fields) {
172
+ const value = record[field];
173
+ if (value !== void 0 && value !== null && typeof value !== "string") return field;
174
+ }
175
+ return null;
176
+ }
159
177
  function validateSkillOp(op, context, index) {
178
+ const badField = malformedStringField(op, [
179
+ "name",
180
+ "content",
181
+ "old_string",
182
+ "new_string",
183
+ "file_path",
184
+ "file_content",
185
+ "absorbed_into"
186
+ ]);
187
+ if (badField) return `skill op ${index}: field ${badField} must be a string`;
160
188
  for (const key of FORBIDDEN_KEYS) if (key in op) return `skill op ${index}: forbidden field ${key}`;
161
189
  const name = (op.name ?? "").trim();
162
190
  if (!name) return `skill op ${index}: name is required`;
@@ -172,7 +200,7 @@ function validateSkillOp(op, context, index) {
172
200
  op.content ?? "",
173
201
  op.new_string ?? ""
174
202
  ].reduce((max, value) => Math.max(max, value.length), 0);
175
- if (action === "write_file" && !(op.file_content ?? op.content ?? "").trim()) return `skill op ${index}: write_file requires file_content`;
203
+ if (action === "write_file" && !(op.file_content ?? "").trim()) return `skill op ${index}: write_file requires file_content`;
176
204
  if (writeBytes > (context.maxSkillContentChars ?? DEFAULT_SKILL_CONTENT_CHARS)) return `skill op ${index}: content exceeds skill budget`;
177
205
  if (action === "restructure") {
178
206
  if (!Array.isArray(op.restructure) || op.restructure.length === 0) return `skill op ${index}: restructure requires a non-empty restructure list`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-plan-validator",
3
3
  "description": "Deterministic validator for model-produced evolution plans (community build)",
4
- "version": "0.3.61",
4
+ "version": "0.3.63",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@lmzhen/dsh-evolution-core": "^0.3.61"
33
+ "@lmzhen/dsh-evolution-core": "^0.3.63"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",