Remove stepCount/stepSize; patterns own their geometry
The stepCount and stepSize knobs were two controls for one quantity users actually care about (reach), and the number of steps is an implementation detail nobody meaningfully tunes. Each pattern has a natural size and resolution — a jitter is inherently small, an arc a broad curve — so those now live as constants in each strategy rather than as global config. - strategies.ts: each pattern defines its own step count and size; MoveContext drops `config` down to pure geometry (start/width/height/rng), and the module no longer imports Config at all (dissolving the type-only-import cycle workaround). line stays byte-for-byte: 250 one-pixel steps. - executor.ts: executePath takes `config` for pacing (stepDelay); the path itself needs nothing from it. - config.ts / cli.ts / move.ts / config.default.json: drop stepCount and stepSize from the type, seed, validation, resolver, CLI flags (-n, -s), and help. stepDelay stays as the one pacing lever. - configFile.ts: tolerate the removed keys instead of rejecting them — every pre-1.3.0 install seeded stepCount, so a hard "unknown key" failure on upgrade is avoided. They're ignored with a one-line stderr notice; genuine unknown keys still error. The -n/--step-count CLI flag (shipped since 1.0.0) is now an unknown option; config files degrade gracefully, command lines don't. Stays in the unpushed 1.3.0 release. 64 tests pass.
This commit is contained in:
+16
-11
@@ -61,8 +61,13 @@ function fixed(points: Point[], bounds: BoundsPolicy): MovementStrategy {
|
||||
};
|
||||
}
|
||||
|
||||
function ctxOf(start: Point, width: number, height: number, config?: Partial<Config>): MoveContext {
|
||||
return { start, width, height, config: { ...DEFAULT_CONFIG, ...config }, rng: Math.random };
|
||||
function ctxOf(start: Point, width: number, height: number): MoveContext {
|
||||
return { start, width, height, rng: Math.random };
|
||||
}
|
||||
|
||||
/** A full `Config` for the executor's pacing; only `stepDelay` matters here. */
|
||||
function cfgOf(config?: Partial<Config>): Config {
|
||||
return { ...DEFAULT_CONFIG, ...config };
|
||||
}
|
||||
|
||||
describe("executePath — outcomes", () => {
|
||||
@@ -74,7 +79,7 @@ describe("executePath — outcomes", () => {
|
||||
{ x: 502, y: 500 },
|
||||
{ x: 503, y: 500 },
|
||||
];
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("completed");
|
||||
// 3 steps + 1 restore.
|
||||
expect(dev.commanded).toEqual([...pts, start]);
|
||||
@@ -90,7 +95,7 @@ describe("executePath — outcomes", () => {
|
||||
];
|
||||
// 2nd getPosition call reports the user elsewhere.
|
||||
dev.overrides.set(2, { x: 9, y: 9 });
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("interrupted");
|
||||
// Commanded points 1 and 2 only; never restored to start.
|
||||
expect(dev.commanded).toEqual([pts[0]!, pts[1]!]);
|
||||
@@ -100,7 +105,7 @@ describe("executePath — outcomes", () => {
|
||||
test("abort policy stops before commanding an out-of-bounds point", async () => {
|
||||
const dev = new FakeDevice(100, 100);
|
||||
const pts = [{ x: 150, y: 10 }]; // x >= width
|
||||
const outcome = await executePath(fixed(pts, "abort"), ctxOf({ x: 10, y: 10 }, 100, 100), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "abort"), ctxOf({ x: 10, y: 10 }, 100, 100), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("aborted");
|
||||
expect(dev.commanded).toEqual([]);
|
||||
});
|
||||
@@ -114,7 +119,7 @@ describe("executePath — bounds policies", () => {
|
||||
{ x: 9999, y: 50 },
|
||||
];
|
||||
// travelRange(100) is inset by EDGE_MARGIN (2) to [2, 97].
|
||||
await executePath(fixed(pts, "clamp"), ctxOf({ x: 50, y: 50 }, 100, 100), dev, noopLog);
|
||||
await executePath(fixed(pts, "clamp"), ctxOf({ x: 50, y: 50 }, 100, 100), dev, noopLog, cfgOf());
|
||||
expect(dev.commanded[0]).toEqual({ x: 2, y: 50 });
|
||||
expect(dev.commanded[1]).toEqual({ x: 97, y: 50 });
|
||||
});
|
||||
@@ -123,7 +128,7 @@ describe("executePath — bounds policies", () => {
|
||||
const dev = new FakeDevice(100, 100);
|
||||
// Inset range [2, 97], span = 95; x=120 -> (120-2)=118, 190-118=72, +2 = 74.
|
||||
const pts = [{ x: 120, y: 50 }];
|
||||
await executePath(fixed(pts, "reflect"), ctxOf({ x: 50, y: 50 }, 100, 100), dev, noopLog);
|
||||
await executePath(fixed(pts, "reflect"), ctxOf({ x: 50, y: 50 }, 100, 100), dev, noopLog, cfgOf());
|
||||
expect(dev.commanded[0]).toEqual({ x: 74, y: 50 });
|
||||
});
|
||||
});
|
||||
@@ -140,7 +145,7 @@ describe("executePath — readback tolerance", () => {
|
||||
// not the user). 2px is within READBACK_TOLERANCE, so the sweep runs on.
|
||||
dev.overrides.set(1, { x: 512, y: 501 });
|
||||
dev.overrides.set(2, { x: 518, y: 499 });
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("completed");
|
||||
expect(dev.commanded).toEqual([...pts, start]);
|
||||
});
|
||||
@@ -154,7 +159,7 @@ describe("executePath — readback tolerance", () => {
|
||||
];
|
||||
// First readback is 3px off -> exceeds the 2px tolerance -> real user.
|
||||
dev.overrides.set(1, { x: 513, y: 500 });
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("interrupted");
|
||||
expect(dev.commanded).toEqual([pts[0]!]);
|
||||
});
|
||||
@@ -165,7 +170,7 @@ describe("executePath — rounding & pacing", () => {
|
||||
const dev = new FakeDevice();
|
||||
const start = { x: 500, y: 500 };
|
||||
const pts = [{ x: 10.4, y: 20.6 }]; // -> (10, 21)
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog);
|
||||
const outcome = await executePath(fixed(pts, "clamp"), ctxOf(start, dev.w, dev.h), dev, noopLog, cfgOf());
|
||||
expect(outcome).toBe("completed");
|
||||
expect(dev.commanded[0]).toEqual({ x: 10, y: 21 });
|
||||
});
|
||||
@@ -176,7 +181,7 @@ describe("executePath — rounding & pacing", () => {
|
||||
{ x: 501, y: 500 },
|
||||
{ x: 502, y: 500 },
|
||||
];
|
||||
await executePath(fixed(pts, "clamp"), ctxOf({ x: 500, y: 500 }, dev.w, dev.h, { stepDelay: 7 }), dev, noopLog);
|
||||
await executePath(fixed(pts, "clamp"), ctxOf({ x: 500, y: 500 }, dev.w, dev.h), dev, noopLog, cfgOf({ stepDelay: 7 }));
|
||||
expect(dev.sleeps).toEqual([7, 7]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user