miaoda-game-devkit 0.10.2 → 0.10.3

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.
@@ -51,9 +51,7 @@ interface StepUntilOptions {
51
51
  /**
52
52
  * Optional read-only state used to make bounded failures actionable.
53
53
  *
54
- * The value is sampled when the bound is exhausted, and additionally at a fixed
55
- * step interval so an exhausted bound can distinguish a run that is still
56
- * progressing from one whose state already settled.
54
+ * The value is sampled when the bound is exhausted.
57
55
  */
58
56
  diagnostics?: () => unknown;
59
57
  /** 测试超时或运行取消时停止继续推进,通常由 playthroughTest 自动传入。 */
@@ -51,9 +51,7 @@ interface StepUntilOptions {
51
51
  /**
52
52
  * Optional read-only state used to make bounded failures actionable.
53
53
  *
54
- * The value is sampled when the bound is exhausted, and additionally at a fixed
55
- * step interval so an exhausted bound can distinguish a run that is still
56
- * progressing from one whose state already settled.
54
+ * The value is sampled when the bound is exhausted.
57
55
  */
58
56
  diagnostics?: () => unknown;
59
57
  /** 测试超时或运行取消时停止继续推进,通常由 playthroughTest 自动传入。 */
@@ -311,39 +311,6 @@ function formatDiagnostics(read) {
311
311
  return `diagnostics() threw: ${String(error)}`;
312
312
  }
313
313
  }
314
- var STAGNATION_SAMPLE_INTERVAL = 32;
315
- var STAGNATION_SAMPLE_MINIMUM = 3;
316
- var StagnationProbe = class {
317
- constructor(read) {
318
- this.read = read;
319
- this.disabled = !read;
320
- }
321
- read;
322
- fingerprint;
323
- unchangedSamples = 0;
324
- disabled = false;
325
- settledAtStep;
326
- sample(step) {
327
- if (this.disabled || step % STAGNATION_SAMPLE_INTERVAL !== 0) return;
328
- let next;
329
- try {
330
- next = JSON.stringify(this.read?.()) ?? "undefined";
331
- } catch {
332
- this.disabled = true;
333
- return;
334
- }
335
- if (this.fingerprint === next) {
336
- this.unchangedSamples += 1;
337
- return;
338
- }
339
- this.fingerprint = next;
340
- this.unchangedSamples = 1;
341
- this.settledAtStep = step;
342
- }
343
- get settled() {
344
- return !this.disabled && this.unchangedSamples >= STAGNATION_SAMPLE_MINIMUM;
345
- }
346
- };
347
314
  function normalizePlaythroughWaiverReason(waiverReason) {
348
315
  if (waiverReason === void 0) return void 0;
349
316
  const reason = waiverReason.trim();
@@ -363,7 +330,6 @@ async function runBoundedUntil(condition, options = {}) {
363
330
  "stepUntil maxSteps must be a safe integer between 0 and 10000."
364
331
  );
365
332
  }
366
- const probe = new StagnationProbe(options.diagnostics);
367
333
  for (let step = 0; step <= maxSteps; step += 1) {
368
334
  throwIfAborted(options.signal);
369
335
  if (condition()) return step;
@@ -372,17 +338,10 @@ async function runBoundedUntil(condition, options = {}) {
372
338
  await options.step?.(step + 1);
373
339
  });
374
340
  throwIfAborted(options.signal);
375
- probe.sample(step + 1);
376
341
  }
377
342
  }
378
343
  const diagnostics = formatDiagnostics(options.diagnostics);
379
344
  const suffix = diagnostics ? ` Last diagnostics: ${diagnostics}` : "";
380
- if (probe.settled) {
381
- throw codedError(
382
- "PLAYTHROUGH_STATE_STAGNANT",
383
- `Playthrough state stopped changing at step ${probe.settledAtStep} of ${maxSteps} and stayed identical until the bound. The run is already settled, so raising maxSteps cannot help: compare the settled state against the outcome this stage asserts. A settled state usually means the game reached a terminal result other than the asserted one, or that the stage never advances the production Controller at all.${suffix}`
384
- );
385
- }
386
345
  const guidance = options.step ? "The step callback ran, but the authoritative outcome did not change." : "No step callback was provided, and the condition did not become true after the stage action. This does not identify a clock problem; inspect the condition, production input wiring, and observed state boundary.";
387
346
  throw codedError(
388
347
  options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
@@ -273,39 +273,6 @@ function formatDiagnostics(read) {
273
273
  return `diagnostics() threw: ${String(error)}`;
274
274
  }
275
275
  }
276
- var STAGNATION_SAMPLE_INTERVAL = 32;
277
- var STAGNATION_SAMPLE_MINIMUM = 3;
278
- var StagnationProbe = class {
279
- constructor(read) {
280
- this.read = read;
281
- this.disabled = !read;
282
- }
283
- read;
284
- fingerprint;
285
- unchangedSamples = 0;
286
- disabled = false;
287
- settledAtStep;
288
- sample(step) {
289
- if (this.disabled || step % STAGNATION_SAMPLE_INTERVAL !== 0) return;
290
- let next;
291
- try {
292
- next = JSON.stringify(this.read?.()) ?? "undefined";
293
- } catch {
294
- this.disabled = true;
295
- return;
296
- }
297
- if (this.fingerprint === next) {
298
- this.unchangedSamples += 1;
299
- return;
300
- }
301
- this.fingerprint = next;
302
- this.unchangedSamples = 1;
303
- this.settledAtStep = step;
304
- }
305
- get settled() {
306
- return !this.disabled && this.unchangedSamples >= STAGNATION_SAMPLE_MINIMUM;
307
- }
308
- };
309
276
  function normalizePlaythroughWaiverReason(waiverReason) {
310
277
  if (waiverReason === void 0) return void 0;
311
278
  const reason = waiverReason.trim();
@@ -325,7 +292,6 @@ async function runBoundedUntil(condition, options = {}) {
325
292
  "stepUntil maxSteps must be a safe integer between 0 and 10000."
326
293
  );
327
294
  }
328
- const probe = new StagnationProbe(options.diagnostics);
329
295
  for (let step = 0; step <= maxSteps; step += 1) {
330
296
  throwIfAborted(options.signal);
331
297
  if (condition()) return step;
@@ -334,17 +300,10 @@ async function runBoundedUntil(condition, options = {}) {
334
300
  await options.step?.(step + 1);
335
301
  });
336
302
  throwIfAborted(options.signal);
337
- probe.sample(step + 1);
338
303
  }
339
304
  }
340
305
  const diagnostics = formatDiagnostics(options.diagnostics);
341
306
  const suffix = diagnostics ? ` Last diagnostics: ${diagnostics}` : "";
342
- if (probe.settled) {
343
- throw codedError(
344
- "PLAYTHROUGH_STATE_STAGNANT",
345
- `Playthrough state stopped changing at step ${probe.settledAtStep} of ${maxSteps} and stayed identical until the bound. The run is already settled, so raising maxSteps cannot help: compare the settled state against the outcome this stage asserts. A settled state usually means the game reached a terminal result other than the asserted one, or that the stage never advances the production Controller at all.${suffix}`
346
- );
347
- }
348
307
  const guidance = options.step ? "The step callback ran, but the authoritative outcome did not change." : "No step callback was provided, and the condition did not become true after the stage action. This does not identify a clock problem; inspect the condition, production input wiring, and observed state boundary.";
349
308
  throw codedError(
350
309
  options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
@@ -265,39 +265,6 @@ function formatDiagnostics(read) {
265
265
  return `diagnostics() threw: ${String(error)}`;
266
266
  }
267
267
  }
268
- var STAGNATION_SAMPLE_INTERVAL = 32;
269
- var STAGNATION_SAMPLE_MINIMUM = 3;
270
- var StagnationProbe = class {
271
- constructor(read) {
272
- this.read = read;
273
- this.disabled = !read;
274
- }
275
- read;
276
- fingerprint;
277
- unchangedSamples = 0;
278
- disabled = false;
279
- settledAtStep;
280
- sample(step) {
281
- if (this.disabled || step % STAGNATION_SAMPLE_INTERVAL !== 0) return;
282
- let next;
283
- try {
284
- next = JSON.stringify(this.read?.()) ?? "undefined";
285
- } catch {
286
- this.disabled = true;
287
- return;
288
- }
289
- if (this.fingerprint === next) {
290
- this.unchangedSamples += 1;
291
- return;
292
- }
293
- this.fingerprint = next;
294
- this.unchangedSamples = 1;
295
- this.settledAtStep = step;
296
- }
297
- get settled() {
298
- return !this.disabled && this.unchangedSamples >= STAGNATION_SAMPLE_MINIMUM;
299
- }
300
- };
301
268
  function normalizePlaythroughWaiverReason(waiverReason) {
302
269
  if (waiverReason === void 0) return void 0;
303
270
  const reason = waiverReason.trim();
@@ -317,7 +284,6 @@ async function runBoundedUntil(condition, options = {}) {
317
284
  "stepUntil maxSteps must be a safe integer between 0 and 10000."
318
285
  );
319
286
  }
320
- const probe = new StagnationProbe(options.diagnostics);
321
287
  for (let step = 0; step <= maxSteps; step += 1) {
322
288
  throwIfAborted(options.signal);
323
289
  if (condition()) return step;
@@ -326,17 +292,10 @@ async function runBoundedUntil(condition, options = {}) {
326
292
  await options.step?.(step + 1);
327
293
  });
328
294
  throwIfAborted(options.signal);
329
- probe.sample(step + 1);
330
295
  }
331
296
  }
332
297
  const diagnostics = formatDiagnostics(options.diagnostics);
333
298
  const suffix = diagnostics ? ` Last diagnostics: ${diagnostics}` : "";
334
- if (probe.settled) {
335
- throw codedError(
336
- "PLAYTHROUGH_STATE_STAGNANT",
337
- `Playthrough state stopped changing at step ${probe.settledAtStep} of ${maxSteps} and stayed identical until the bound. The run is already settled, so raising maxSteps cannot help: compare the settled state against the outcome this stage asserts. A settled state usually means the game reached a terminal result other than the asserted one, or that the stage never advances the production Controller at all.${suffix}`
338
- );
339
- }
340
299
  const guidance = options.step ? "The step callback ran, but the authoritative outcome did not change." : "No step callback was provided, and the condition did not become true after the stage action. This does not identify a clock problem; inspect the condition, production input wiring, and observed state boundary.";
341
300
  throw codedError(
342
301
  options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
@@ -1308,8 +1267,6 @@ function repairGuidance(code) {
1308
1267
  return "The stage ran and asserted, but its observable state matched the previous milestone. Preserve the intended gameplay result and observe the same production Controller rendered by <App />. Do not substitute arbitrary labels or a weaker state change.";
1309
1268
  case "PLAYTHROUGH_BOUND_EXHAUSTED":
1310
1269
  return "First read the phase or result field of Last diagnostics. If the run already reached a terminal result other than the one asserted, the game is over and the bound is irrelevant: assert the result the shipped constants actually produce (loss, draw, and ranking are legitimate terminal results), or fix the mechanic that was supposed to make the intended objective reachable. Raising maxSteps or rewriting the in-test play order cannot pass a finished game. If the run is still mid-game, keep the intended outcome unchanged and confirm that each deterministic step advances the same production Controller rendered by <App />; if state remains unchanged, inject ManualGameClock through the production App factory and observe that Controller through Telemetry. Never replace the outcome with navigation, an intermediate phase, a no-op step, or a weaker assertion, and never retune the production constants that define the challenge.";
1311
- case "PLAYTHROUGH_STATE_STAGNANT":
1312
- return "The observed state stopped changing well before the bound, so the bound is not the problem and raising maxSteps cannot help. Two causes: the run already reached a terminal result other than the one asserted \u2014 assert the result the shipped constants actually produce, or fix the mechanic meant to make the intended objective reachable \u2014 or the stage never advances the production Controller at all, in which case inject ManualGameClock through the production App factory and observe that Controller through Telemetry. Do not retune production constants and do not weaken the assertion.";
1313
1270
  case "PLAYTHROUGH_OUTCOME_NOT_REACHED":
1314
1271
  return "The stage action completed, but its until condition never became true. Inspect TRACE and Last diagnostics, then confirm that the production DOM input reaches the rendered App, until describes the result caused by this stage, and observe reads the matching authoritative state when used. Add a deterministic step only if the gameplay is actually driven by time or frames; do not add a no-op step or weaken the intended outcome.";
1315
1272
  case "PLAYTHROUGH_CLOCK_NOT_ADVANCED":
@@ -231,39 +231,6 @@ function formatDiagnostics(read) {
231
231
  return `diagnostics() threw: ${String(error)}`;
232
232
  }
233
233
  }
234
- var STAGNATION_SAMPLE_INTERVAL = 32;
235
- var STAGNATION_SAMPLE_MINIMUM = 3;
236
- var StagnationProbe = class {
237
- constructor(read) {
238
- this.read = read;
239
- this.disabled = !read;
240
- }
241
- read;
242
- fingerprint;
243
- unchangedSamples = 0;
244
- disabled = false;
245
- settledAtStep;
246
- sample(step) {
247
- if (this.disabled || step % STAGNATION_SAMPLE_INTERVAL !== 0) return;
248
- let next;
249
- try {
250
- next = JSON.stringify(this.read?.()) ?? "undefined";
251
- } catch {
252
- this.disabled = true;
253
- return;
254
- }
255
- if (this.fingerprint === next) {
256
- this.unchangedSamples += 1;
257
- return;
258
- }
259
- this.fingerprint = next;
260
- this.unchangedSamples = 1;
261
- this.settledAtStep = step;
262
- }
263
- get settled() {
264
- return !this.disabled && this.unchangedSamples >= STAGNATION_SAMPLE_MINIMUM;
265
- }
266
- };
267
234
  function normalizePlaythroughWaiverReason(waiverReason) {
268
235
  if (waiverReason === void 0) return void 0;
269
236
  const reason = waiverReason.trim();
@@ -283,7 +250,6 @@ async function runBoundedUntil(condition, options = {}) {
283
250
  "stepUntil maxSteps must be a safe integer between 0 and 10000."
284
251
  );
285
252
  }
286
- const probe = new StagnationProbe(options.diagnostics);
287
253
  for (let step = 0; step <= maxSteps; step += 1) {
288
254
  throwIfAborted(options.signal);
289
255
  if (condition()) return step;
@@ -292,17 +258,10 @@ async function runBoundedUntil(condition, options = {}) {
292
258
  await options.step?.(step + 1);
293
259
  });
294
260
  throwIfAborted(options.signal);
295
- probe.sample(step + 1);
296
261
  }
297
262
  }
298
263
  const diagnostics = formatDiagnostics(options.diagnostics);
299
264
  const suffix = diagnostics ? ` Last diagnostics: ${diagnostics}` : "";
300
- if (probe.settled) {
301
- throw codedError(
302
- "PLAYTHROUGH_STATE_STAGNANT",
303
- `Playthrough state stopped changing at step ${probe.settledAtStep} of ${maxSteps} and stayed identical until the bound. The run is already settled, so raising maxSteps cannot help: compare the settled state against the outcome this stage asserts. A settled state usually means the game reached a terminal result other than the asserted one, or that the stage never advances the production Controller at all.${suffix}`
304
- );
305
- }
306
265
  const guidance = options.step ? "The step callback ran, but the authoritative outcome did not change." : "No step callback was provided, and the condition did not become true after the stage action. This does not identify a clock problem; inspect the condition, production input wiring, and observed state boundary.";
307
266
  throw codedError(
308
267
  options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
@@ -1274,8 +1233,6 @@ function repairGuidance(code) {
1274
1233
  return "The stage ran and asserted, but its observable state matched the previous milestone. Preserve the intended gameplay result and observe the same production Controller rendered by <App />. Do not substitute arbitrary labels or a weaker state change.";
1275
1234
  case "PLAYTHROUGH_BOUND_EXHAUSTED":
1276
1235
  return "First read the phase or result field of Last diagnostics. If the run already reached a terminal result other than the one asserted, the game is over and the bound is irrelevant: assert the result the shipped constants actually produce (loss, draw, and ranking are legitimate terminal results), or fix the mechanic that was supposed to make the intended objective reachable. Raising maxSteps or rewriting the in-test play order cannot pass a finished game. If the run is still mid-game, keep the intended outcome unchanged and confirm that each deterministic step advances the same production Controller rendered by <App />; if state remains unchanged, inject ManualGameClock through the production App factory and observe that Controller through Telemetry. Never replace the outcome with navigation, an intermediate phase, a no-op step, or a weaker assertion, and never retune the production constants that define the challenge.";
1277
- case "PLAYTHROUGH_STATE_STAGNANT":
1278
- return "The observed state stopped changing well before the bound, so the bound is not the problem and raising maxSteps cannot help. Two causes: the run already reached a terminal result other than the one asserted \u2014 assert the result the shipped constants actually produce, or fix the mechanic meant to make the intended objective reachable \u2014 or the stage never advances the production Controller at all, in which case inject ManualGameClock through the production App factory and observe that Controller through Telemetry. Do not retune production constants and do not weaken the assertion.";
1279
1236
  case "PLAYTHROUGH_OUTCOME_NOT_REACHED":
1280
1237
  return "The stage action completed, but its until condition never became true. Inspect TRACE and Last diagnostics, then confirm that the production DOM input reaches the rendered App, until describes the result caused by this stage, and observe reads the matching authoritative state when used. Add a deterministic step only if the gameplay is actually driven by time or frames; do not add a no-op step or weaken the intended outcome.";
1281
1238
  case "PLAYTHROUGH_CLOCK_NOT_ADVANCED":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-game-devkit",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Shared React and Phaser game lint plus deterministic testing tools for Miaoda games",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,6 @@
13
13
  "esModuleInterop": true,
14
14
  "noEmit": true,
15
15
  "strict": true,
16
- "noUnusedLocals": true,
17
- "noUnusedParameters": true,
18
16
  "noFallthroughCasesInSwitch": true,
19
17
  "noUncheckedSideEffectImports": true,
20
18
  "skipLibCheck": true