promptwheel 0.7.11 → 0.7.12
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/bin/promptwheel.d.ts +2 -0
- package/bin/promptwheel.mjs +13 -4
- package/package.json +1 -1
package/bin/promptwheel.d.ts
CHANGED
|
@@ -158,6 +158,8 @@ export interface MetricResult extends Evaluation {
|
|
|
158
158
|
retained?: number | null;
|
|
159
159
|
gamingReason?: string;
|
|
160
160
|
/** Set when a declared override cleared a `gamed` or an `unprovable` on this metric. */
|
|
161
|
+
/** `true`: a guard this change adds, unmeasurable at base because its scanner did not exist there. It starts counting from head. */
|
|
162
|
+
adopted?: true;
|
|
161
163
|
allowed?: true;
|
|
162
164
|
/** Present (`true`) only when this guarded metric regressed, no reason was declared, and `allowable: true` means a `--allow` / trailer reason would clear it. */
|
|
163
165
|
allowable?: true;
|
package/bin/promptwheel.mjs
CHANGED
|
@@ -324,7 +324,10 @@ function checkMandates(repo, base, head, cfg, baseMandates) {
|
|
|
324
324
|
const headKeys = new Set(headList.filter((m) => m && m.name).map(key));
|
|
325
325
|
const kept = (Array.isArray(baseMandates) ? baseMandates : []).filter((m) => m && m.name && !headKeys.has(key(m)))
|
|
326
326
|
.map((m) => (headNames.has(m.name) ? { ...m, __edited: true } : { ...m, __removed: true }));
|
|
327
|
-
|
|
327
|
+
// a rule this change adds does not apply to the change adding it: the commit that signs a contract adds the
|
|
328
|
+
// very files the contract protects. Deleting or narrowing a rule stays caught, through the base list above.
|
|
329
|
+
const baseNames = new Set((Array.isArray(baseMandates) ? baseMandates : []).map((m) => m && m.name));
|
|
330
|
+
const mandates = [...headList.filter((m) => m && baseNames.has(m.name)), ...kept];
|
|
328
331
|
if (!mandates.length) return [];
|
|
329
332
|
let changed = [];
|
|
330
333
|
try { changed = git(['diff', '--name-only', base, head], repo).split('\n').filter(Boolean); } catch { return []; }
|
|
@@ -721,8 +724,14 @@ function gate(repo, opts) {
|
|
|
721
724
|
|
|
722
725
|
const before = measureAt(repo, base, cfg, repeat);
|
|
723
726
|
const after = measureAt(repo, head, cfg, repeat);
|
|
727
|
+
// a guard this change adds has no value at base, because its scanner did not exist there. That is adoption,
|
|
728
|
+
// not a failure: it starts counting from head. Removing a guard is still caught (gateWeakenings), and a guard the
|
|
729
|
+
// base contract already had still fails when it cannot be measured. A zero-config run has no contract to adopt.
|
|
730
|
+
const baseDefs = opts.config ? null : gateDefAtRef(repo, base);
|
|
731
|
+
const adopted = (name) => !opts.config && !(baseDefs && baseDefs.metrics.has(name));
|
|
724
732
|
const metrics = cfg.metrics.map((m) => {
|
|
725
733
|
const ev = evaluate(m, before[m.name], after[m.name], repeat);
|
|
734
|
+
if (ev.status === 'unmeasurable' && ev.before == null && ev.after != null && adopted(m.name)) { ev.ok = true; ev.adopted = true; }
|
|
726
735
|
return { name: m.name, direction: m.direction || 'up', guard: !!m.guard, ...ev };
|
|
727
736
|
});
|
|
728
737
|
// Section 3 (gaming detection), on by default: mutates `metrics` and yields the gate record
|
|
@@ -924,9 +933,9 @@ const PRESETS = {
|
|
|
924
933
|
metrics: [
|
|
925
934
|
{ name: 'tests_pass', cmd: '__TESTCMD__', extract: 'exit', direction: 'pass', guard: true },
|
|
926
935
|
{ name: 'test_count', cmd: 'grep -rIoE "\\b(it|test|describe) ?\\(|def test_" --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'up', guard: true, gamingCheck: false },
|
|
927
|
-
{ name: 'skipped_tests', cmd: 'grep -rIoE "\\.(skip|only) ?\\(|xit ?\\(|@pytest\\.mark\\.skip" --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'down', guard: true, gamingCheck: false },
|
|
928
|
-
{ name: 'suppressions', cmd: 'grep -rIoE "eslint-disable|@ts-(ignore|nocheck)|# ?type: ?ignore|# ?noqa|# ?nosec|//nolint|#!?\\[allow\\(" --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'down', guard: true, gamingCheck: false },
|
|
929
|
-
{ name: 'assertions', cmd: 'grep -rIoE "expect ?\\(|\\bassert|\\bt\\.(is|deepEqual|throws|truthy|falsy|not|ok) ?\\(" --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'up', guard: true, gamingCheck: false },
|
|
936
|
+
{ name: 'skipped_tests', cmd: 'grep -rIoE "\\.(skip|only) ?\\(|xit ?\\(|@pytest\\.mark\\.skip" --exclude-dir=node_modules --exclude-dir=.promptwheel --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'down', guard: true, gamingCheck: false },
|
|
937
|
+
{ name: 'suppressions', cmd: 'grep -rIoE "eslint-disable|@ts-(ignore|nocheck)|# ?type: ?ignore|# ?noqa|# ?nosec|//nolint|#!?\\[allow\\(" --exclude-dir=node_modules --exclude-dir=.promptwheel --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'down', guard: true, gamingCheck: false },
|
|
938
|
+
{ name: 'assertions', cmd: 'grep -rIoE "expect ?\\(|\\bassert|\\bt\\.(is|deepEqual|throws|truthy|falsy|not|ok) ?\\(" --exclude-dir=node_modules --exclude-dir=.promptwheel --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.next --exclude-dir=out --exclude-dir=lib-cov --exclude-dir=__pycache__ --exclude-dir=.pytest_cache --exclude-dir=target --exclude-dir=.venv --exclude-dir=venv --exclude=promptwheel.config.json . 2>/dev/null | wc -l | tr -d " "', extract: 'number', direction: 'up', guard: true, gamingCheck: false },
|
|
930
939
|
] },
|
|
931
940
|
'no-ai-tells': { desc: 'opt-in: fail the gate if the em-dash count rises (an AI writing tell); some projects use them on purpose, so it is not a default',
|
|
932
941
|
metrics: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "promptwheel",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.12",
|
|
4
4
|
"description": "A deterministic, zero-LLM check for your coding loop. It proves every change earned its win by re-running the result from the agent's source edits alone, so a green that came from editing the test reads GAMED. Runs in CI or a Claude Code hook, or import { check } in process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|