miaoda-game-devkit 0.10.1 → 0.10.2
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/dist/react/testing.d.mts
CHANGED
|
@@ -50,7 +50,10 @@ interface StepUntilOptions {
|
|
|
50
50
|
step?: (step: number) => void | Promise<void>;
|
|
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
57
|
*/
|
|
55
58
|
diagnostics?: () => unknown;
|
|
56
59
|
/** 测试超时或运行取消时停止继续推进,通常由 playthroughTest 自动传入。 */
|
package/dist/react/testing.d.ts
CHANGED
|
@@ -50,7 +50,10 @@ interface StepUntilOptions {
|
|
|
50
50
|
step?: (step: number) => void | Promise<void>;
|
|
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
57
|
*/
|
|
55
58
|
diagnostics?: () => unknown;
|
|
56
59
|
/** 测试超时或运行取消时停止继续推进,通常由 playthroughTest 自动传入。 */
|
package/dist/react/testing.js
CHANGED
|
@@ -311,6 +311,39 @@ 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
|
+
};
|
|
314
347
|
function normalizePlaythroughWaiverReason(waiverReason) {
|
|
315
348
|
if (waiverReason === void 0) return void 0;
|
|
316
349
|
const reason = waiverReason.trim();
|
|
@@ -330,6 +363,7 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
330
363
|
"stepUntil maxSteps must be a safe integer between 0 and 10000."
|
|
331
364
|
);
|
|
332
365
|
}
|
|
366
|
+
const probe = new StagnationProbe(options.diagnostics);
|
|
333
367
|
for (let step = 0; step <= maxSteps; step += 1) {
|
|
334
368
|
throwIfAborted(options.signal);
|
|
335
369
|
if (condition()) return step;
|
|
@@ -338,11 +372,18 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
338
372
|
await options.step?.(step + 1);
|
|
339
373
|
});
|
|
340
374
|
throwIfAborted(options.signal);
|
|
375
|
+
probe.sample(step + 1);
|
|
341
376
|
}
|
|
342
377
|
}
|
|
343
378
|
const diagnostics = formatDiagnostics(options.diagnostics);
|
|
344
|
-
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.";
|
|
345
379
|
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
|
+
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.";
|
|
346
387
|
throw codedError(
|
|
347
388
|
options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
|
|
348
389
|
`Playthrough outcome was not reached within ${maxSteps} steps. ${guidance}${suffix}`
|
package/dist/react/testing.mjs
CHANGED
|
@@ -273,6 +273,39 @@ 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
|
+
};
|
|
276
309
|
function normalizePlaythroughWaiverReason(waiverReason) {
|
|
277
310
|
if (waiverReason === void 0) return void 0;
|
|
278
311
|
const reason = waiverReason.trim();
|
|
@@ -292,6 +325,7 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
292
325
|
"stepUntil maxSteps must be a safe integer between 0 and 10000."
|
|
293
326
|
);
|
|
294
327
|
}
|
|
328
|
+
const probe = new StagnationProbe(options.diagnostics);
|
|
295
329
|
for (let step = 0; step <= maxSteps; step += 1) {
|
|
296
330
|
throwIfAborted(options.signal);
|
|
297
331
|
if (condition()) return step;
|
|
@@ -300,11 +334,18 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
300
334
|
await options.step?.(step + 1);
|
|
301
335
|
});
|
|
302
336
|
throwIfAborted(options.signal);
|
|
337
|
+
probe.sample(step + 1);
|
|
303
338
|
}
|
|
304
339
|
}
|
|
305
340
|
const diagnostics = formatDiagnostics(options.diagnostics);
|
|
306
|
-
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
341
|
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
|
+
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.";
|
|
308
349
|
throw codedError(
|
|
309
350
|
options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
|
|
310
351
|
`Playthrough outcome was not reached within ${maxSteps} steps. ${guidance}${suffix}`
|
|
@@ -265,6 +265,39 @@ 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
|
+
};
|
|
268
301
|
function normalizePlaythroughWaiverReason(waiverReason) {
|
|
269
302
|
if (waiverReason === void 0) return void 0;
|
|
270
303
|
const reason = waiverReason.trim();
|
|
@@ -284,6 +317,7 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
284
317
|
"stepUntil maxSteps must be a safe integer between 0 and 10000."
|
|
285
318
|
);
|
|
286
319
|
}
|
|
320
|
+
const probe = new StagnationProbe(options.diagnostics);
|
|
287
321
|
for (let step = 0; step <= maxSteps; step += 1) {
|
|
288
322
|
throwIfAborted(options.signal);
|
|
289
323
|
if (condition()) return step;
|
|
@@ -292,11 +326,18 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
292
326
|
await options.step?.(step + 1);
|
|
293
327
|
});
|
|
294
328
|
throwIfAborted(options.signal);
|
|
329
|
+
probe.sample(step + 1);
|
|
295
330
|
}
|
|
296
331
|
}
|
|
297
332
|
const diagnostics = formatDiagnostics(options.diagnostics);
|
|
298
|
-
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.";
|
|
299
333
|
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
|
+
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.";
|
|
300
341
|
throw codedError(
|
|
301
342
|
options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
|
|
302
343
|
`Playthrough outcome was not reached within ${maxSteps} steps. ${guidance}${suffix}`
|
|
@@ -1266,7 +1307,9 @@ function repairGuidance(code) {
|
|
|
1266
1307
|
case "STAGE_STATE_UNCHANGED":
|
|
1267
1308
|
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.";
|
|
1268
1309
|
case "PLAYTHROUGH_BOUND_EXHAUSTED":
|
|
1269
|
-
return "
|
|
1310
|
+
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.";
|
|
1270
1313
|
case "PLAYTHROUGH_OUTCOME_NOT_REACHED":
|
|
1271
1314
|
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.";
|
|
1272
1315
|
case "PLAYTHROUGH_CLOCK_NOT_ADVANCED":
|
|
@@ -231,6 +231,39 @@ 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
|
+
};
|
|
234
267
|
function normalizePlaythroughWaiverReason(waiverReason) {
|
|
235
268
|
if (waiverReason === void 0) return void 0;
|
|
236
269
|
const reason = waiverReason.trim();
|
|
@@ -250,6 +283,7 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
250
283
|
"stepUntil maxSteps must be a safe integer between 0 and 10000."
|
|
251
284
|
);
|
|
252
285
|
}
|
|
286
|
+
const probe = new StagnationProbe(options.diagnostics);
|
|
253
287
|
for (let step = 0; step <= maxSteps; step += 1) {
|
|
254
288
|
throwIfAborted(options.signal);
|
|
255
289
|
if (condition()) return step;
|
|
@@ -258,11 +292,18 @@ async function runBoundedUntil(condition, options = {}) {
|
|
|
258
292
|
await options.step?.(step + 1);
|
|
259
293
|
});
|
|
260
294
|
throwIfAborted(options.signal);
|
|
295
|
+
probe.sample(step + 1);
|
|
261
296
|
}
|
|
262
297
|
}
|
|
263
298
|
const diagnostics = formatDiagnostics(options.diagnostics);
|
|
264
|
-
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.";
|
|
265
299
|
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
|
+
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.";
|
|
266
307
|
throw codedError(
|
|
267
308
|
options.step ? "PLAYTHROUGH_BOUND_EXHAUSTED" : "PLAYTHROUGH_OUTCOME_NOT_REACHED",
|
|
268
309
|
`Playthrough outcome was not reached within ${maxSteps} steps. ${guidance}${suffix}`
|
|
@@ -1232,7 +1273,9 @@ function repairGuidance(code) {
|
|
|
1232
1273
|
case "STAGE_STATE_UNCHANGED":
|
|
1233
1274
|
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.";
|
|
1234
1275
|
case "PLAYTHROUGH_BOUND_EXHAUSTED":
|
|
1235
|
-
return "
|
|
1276
|
+
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.";
|
|
1236
1279
|
case "PLAYTHROUGH_OUTCOME_NOT_REACHED":
|
|
1237
1280
|
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.";
|
|
1238
1281
|
case "PLAYTHROUGH_CLOCK_NOT_ADVANCED":
|